Skip to content

Commit e5116eb

Browse files
committed
bpo-29861: release references to multiprocessing Pool tasks (python#743)
* bpo-29861: release references to multiprocessing Pool tasks Release references to tasks, their arguments and their results as soon as they are finished, instead of keeping them alive until another task arrives. * Comments in test (cherry picked from commit 8988945)
1 parent 6a45811 commit e5116eb

File tree

3 files changed

+36
-61
lines changed

3 files changed

+36
-61
lines changed

Lib/multiprocessing/pool.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,8 @@ def worker(inqueue, outqueue, initializer=None, initargs=(), maxtasks=None,
128128
util.debug("Possible encoding error while sending result: %s" % (
129129
wrapped))
130130
put((job, i, (False, wrapped)))
131+
132+
task = job = result = func = args = kwds = None
131133
completed += 1
132134
util.debug('worker exiting after %d tasks' % completed)
133135

@@ -402,10 +404,11 @@ def _handle_tasks(taskqueue, put, outqueue, pool, cache):
402404
if set_length:
403405
util.debug('doing set_length()')
404406
set_length(i+1)
407+
finally:
408+
task = taskseq = job = None
405409
else:
406410
util.debug('task handler got sentinel')
407411

408-
409412
try:
410413
# tell result handler to finish when cache is empty
411414
util.debug('task handler sending sentinel to result handler')
@@ -445,6 +448,7 @@ def _handle_results(outqueue, get, cache):
445448
cache[job]._set(i, obj)
446449
except KeyError:
447450
pass
451+
task = job = obj = None
448452

449453
while cache and thread._state != TERMINATE:
450454
try:
@@ -461,6 +465,7 @@ def _handle_results(outqueue, get, cache):
461465
cache[job]._set(i, obj)
462466
except KeyError:
463467
pass
468+
task = job = obj = None
464469

465470
if hasattr(outqueue, '_reader'):
466471
util.debug('ensuring that outqueue is not full')

Lib/test/_test_multiprocessing.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import logging
1919
import struct
2020
import operator
21+
import weakref
2122
import test.support
2223
import test.support.script_helper
2324

@@ -1668,6 +1669,19 @@ def sqr(x, wait=0.0):
16681669
def mul(x, y):
16691670
return x*y
16701671

1672+
def identity(x):
1673+
return x
1674+
1675+
class CountedObject(object):
1676+
n_instances = 0
1677+
1678+
def __new__(cls):
1679+
cls.n_instances += 1
1680+
return object.__new__(cls)
1681+
1682+
def __del__(self):
1683+
type(self).n_instances -= 1
1684+
16711685
class SayWhenError(ValueError): pass
16721686

16731687
def exception_throwing_generator(total, when):
@@ -1676,6 +1690,7 @@ def exception_throwing_generator(total, when):
16761690
raise SayWhenError("Somebody said when")
16771691
yield i
16781692

1693+
16791694
class _TestPool(BaseTestCase):
16801695

16811696
@classmethod
@@ -1910,6 +1925,19 @@ def test_wrapped_exception(self):
19101925
with self.assertRaises(RuntimeError):
19111926
p.apply(self._test_wrapped_exception)
19121927

1928+
def test_release_task_refs(self):
1929+
# Issue #29861: task arguments and results should not be kept
1930+
# alive after we are done with them.
1931+
objs = [CountedObject() for i in range(10)]
1932+
refs = [weakref.ref(o) for o in objs]
1933+
self.pool.map(identity, objs)
1934+
1935+
del objs
1936+
self.assertEqual(set(wr() for wr in refs), {None})
1937+
# With a process pool, copies of the objects are returned, check
1938+
# they were released too.
1939+
self.assertEqual(CountedObject.n_instances, 0)
1940+
19131941

19141942
def raising():
19151943
raise KeyError("key")

Misc/NEWS

Lines changed: 2 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -10,24 +10,6 @@ Release date: XXXX-XX-XX
1010
Core and Builtins
1111
-----------------
1212

13-
- bpo-28876: ``bool(range)`` works even if ``len(range)``
14-
raises :exc:`OverflowError`.
15-
16-
- bpo-29600: Fix wrapping coroutine return values in StopIteration.
17-
18-
- Issue #29537: Restore runtime compatibility with bytecode files generated by
19-
CPython 3.5.0 to 3.5.2, and adjust the eval loop to avoid the problems that
20-
could be caused by the malformed variant of the BUILD_MAP_UNPACK_WITH_CALL
21-
opcode that they may contain. Patch by Petr Viktorin, Serhiy Storchaka,
22-
and Nick Coghlan.
23-
24-
- Issue #28598: Support __rmod__ for subclasses of str being called before
25-
str.__mod__. Patch by Martijn Pieters.
26-
27-
- bpo-29602: Fix incorrect handling of signed zeros in complex constructor for
28-
complex subclasses and for inputs having a __complex__ method. Patch
29-
by Serhiy Storchaka.
30-
3113
- bpo-29347: Fixed possibly dereferencing undefined pointers
3214
when creating weakref objects.
3315

@@ -46,43 +28,8 @@ Extension Modules
4628
Library
4729
-------
4830

49-
- bpo-29884: faulthandler: Restore the old sigaltstack during teardown.
50-
Patch by Christophe Zeitouny.
51-
52-
- bpo-25455: Fixed crashes in repr of recursive buffered file-like objects.
53-
54-
- bpo-29800: Fix crashes in partial.__repr__ if the keys of partial.keywords
55-
are not strings. Patch by Michael Seifert.
56-
57-
- bpo-29742: get_extra_info() raises exception if get called on closed ssl transport.
58-
Patch by Nikolay Kim.
59-
60-
- bpo-8256: Fixed possible failing or crashing input() if attributes "encoding"
61-
or "errors" of sys.stdin or sys.stdout are not set or are not strings.
62-
63-
- bpo-28298: Fix a bug that prevented array 'Q', 'L' and 'I' from accepting big
64-
intables (objects that have __int__) as elements. Patch by Oren Milman.
65-
66-
- bpo-29615: SimpleXMLRPCDispatcher no longer chains KeyError (or any other
67-
exception) to exception(s) raised in the dispatched methods.
68-
Patch by Petr Motejlek.
69-
70-
- bpo-29704: asyncio.subprocess.SubprocessStreamProtocol no longer closes before
71-
all pipes are closed.
72-
73-
- bpo-29703: Fix asyncio to support instantiation of new event loops
74-
in child processes.
75-
76-
- bpo-29376: Fix assertion error in threading._DummyThread.is_alive().
77-
78-
- bpo-29110: Fix file object leak in aifc.open() when file is given as a
79-
filesystem path and is not in valid AIFF format. Patch by Anthony Zhang.
80-
81-
- Issue #28961: Fix unittest.mock._Call helper: don't ignore the name parameter
82-
anymore. Patch written by Jiajun Huang.
83-
84-
- bpo-29532: Altering a kwarg dictionary passed to functools.partial()
85-
no longer affects a partial object after creation.
31+
- bpo-29861: Release references to tasks, their arguments and their results
32+
as soon as they are finished in multiprocessing.Pool.
8633

8734
- Issue #28556: Various updates to typing module: typing.Counter, typing.ChainMap,
8835
improved ABC caching, etc. Original PRs by Jelle Zijlstra, Ivan Levkivskyi,
@@ -141,11 +88,6 @@ C API
14188
Documentation
14289
-------------
14390

144-
- bpo-28929: Link the documentation to its source file on GitHub.
145-
146-
- bpo-25008: Document smtpd.py as effectively deprecated and add a pointer to
147-
aiosmtpd, a third-party asyncio-based replacement.
148-
14991
- Issue #26355: Add canonical header link on each page to corresponding major
15092
version of the documentation. Patch by Matthias Bussonnier.
15193

0 commit comments

Comments
 (0)