Skip to content

Commit 8988945

Browse files
authored
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
1 parent e304e33 commit 8988945

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

@@ -1738,6 +1739,19 @@ def raise_large_valuerror(wait):
17381739
time.sleep(wait)
17391740
raise ValueError("x" * 1024**2)
17401741

1742+
def identity(x):
1743+
return x
1744+
1745+
class CountedObject(object):
1746+
n_instances = 0
1747+
1748+
def __new__(cls):
1749+
cls.n_instances += 1
1750+
return object.__new__(cls)
1751+
1752+
def __del__(self):
1753+
type(self).n_instances -= 1
1754+
17411755
class SayWhenError(ValueError): pass
17421756

17431757
def exception_throwing_generator(total, when):
@@ -1746,6 +1760,7 @@ def exception_throwing_generator(total, when):
17461760
raise SayWhenError("Somebody said when")
17471761
yield i
17481762

1763+
17491764
class _TestPool(BaseTestCase):
17501765

17511766
@classmethod
@@ -2000,6 +2015,19 @@ def test_map_no_failfast(self):
20002015
# check that we indeed waited for all jobs
20012016
self.assertGreater(time.time() - t_start, 0.9)
20022017

2018+
def test_release_task_refs(self):
2019+
# Issue #29861: task arguments and results should not be kept
2020+
# alive after we are done with them.
2021+
objs = [CountedObject() for i in range(10)]
2022+
refs = [weakref.ref(o) for o in objs]
2023+
self.pool.map(identity, objs)
2024+
2025+
del objs
2026+
self.assertEqual(set(wr() for wr in refs), {None})
2027+
# With a process pool, copies of the objects are returned, check
2028+
# they were released too.
2029+
self.assertEqual(CountedObject.n_instances, 0)
2030+
20032031

20042032
def raising():
20052033
raise KeyError("key")

Misc/NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -287,6 +287,9 @@ Extension Modules
287287
Library
288288
-------
289289

290+
- bpo-29861: Release references to tasks, their arguments and their results
291+
as soon as they are finished in multiprocessing.Pool.
292+
290293
- bpo-19930: The mode argument of os.makedirs() no longer affects the file
291294
permission bits of newly-created intermediate-level directories.
292295

0 commit comments

Comments
 (0)