Skip to content

Commit 80cb6ed

Browse files
authored
bpo-29861: release references to multiprocessing Pool tasks (#743) (#801)
* bpo-29861: release references to multiprocessing Pool tasks (#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) * Fix Misc/NEWS??
1 parent 6a45811 commit 80cb6ed

File tree

3 files changed

+37
-1
lines changed

3 files changed

+37
-1
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: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,9 @@ Extension Modules
4646
Library
4747
-------
4848

49+
- bpo-29861: Release references to tasks, their arguments and their results
50+
as soon as they are finished in multiprocessing.Pool.
51+
4952
- bpo-29884: faulthandler: Restore the old sigaltstack during teardown.
5053
Patch by Christophe Zeitouny.
5154

0 commit comments

Comments
 (0)