mirror of
https://github.com/python/cpython.git
synced 2025-10-05 22:51:56 +00:00
* 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 8988945cdc
)
* Fix Misc/NEWS??
This commit is contained in:
parent
6a45811d06
commit
80cb6ed4db
3 changed files with 37 additions and 1 deletions
|
@ -128,6 +128,8 @@ def worker(inqueue, outqueue, initializer=None, initargs=(), maxtasks=None,
|
|||
util.debug("Possible encoding error while sending result: %s" % (
|
||||
wrapped))
|
||||
put((job, i, (False, wrapped)))
|
||||
|
||||
task = job = result = func = args = kwds = None
|
||||
completed += 1
|
||||
util.debug('worker exiting after %d tasks' % completed)
|
||||
|
||||
|
@ -402,10 +404,11 @@ class Pool(object):
|
|||
if set_length:
|
||||
util.debug('doing set_length()')
|
||||
set_length(i+1)
|
||||
finally:
|
||||
task = taskseq = job = None
|
||||
else:
|
||||
util.debug('task handler got sentinel')
|
||||
|
||||
|
||||
try:
|
||||
# tell result handler to finish when cache is empty
|
||||
util.debug('task handler sending sentinel to result handler')
|
||||
|
@ -445,6 +448,7 @@ class Pool(object):
|
|||
cache[job]._set(i, obj)
|
||||
except KeyError:
|
||||
pass
|
||||
task = job = obj = None
|
||||
|
||||
while cache and thread._state != TERMINATE:
|
||||
try:
|
||||
|
@ -461,6 +465,7 @@ class Pool(object):
|
|||
cache[job]._set(i, obj)
|
||||
except KeyError:
|
||||
pass
|
||||
task = job = obj = None
|
||||
|
||||
if hasattr(outqueue, '_reader'):
|
||||
util.debug('ensuring that outqueue is not full')
|
||||
|
|
|
@ -18,6 +18,7 @@ import random
|
|||
import logging
|
||||
import struct
|
||||
import operator
|
||||
import weakref
|
||||
import test.support
|
||||
import test.support.script_helper
|
||||
|
||||
|
@ -1668,6 +1669,19 @@ def sqr(x, wait=0.0):
|
|||
def mul(x, y):
|
||||
return x*y
|
||||
|
||||
def identity(x):
|
||||
return x
|
||||
|
||||
class CountedObject(object):
|
||||
n_instances = 0
|
||||
|
||||
def __new__(cls):
|
||||
cls.n_instances += 1
|
||||
return object.__new__(cls)
|
||||
|
||||
def __del__(self):
|
||||
type(self).n_instances -= 1
|
||||
|
||||
class SayWhenError(ValueError): pass
|
||||
|
||||
def exception_throwing_generator(total, when):
|
||||
|
@ -1676,6 +1690,7 @@ def exception_throwing_generator(total, when):
|
|||
raise SayWhenError("Somebody said when")
|
||||
yield i
|
||||
|
||||
|
||||
class _TestPool(BaseTestCase):
|
||||
|
||||
@classmethod
|
||||
|
@ -1910,6 +1925,19 @@ class _TestPool(BaseTestCase):
|
|||
with self.assertRaises(RuntimeError):
|
||||
p.apply(self._test_wrapped_exception)
|
||||
|
||||
def test_release_task_refs(self):
|
||||
# Issue #29861: task arguments and results should not be kept
|
||||
# alive after we are done with them.
|
||||
objs = [CountedObject() for i in range(10)]
|
||||
refs = [weakref.ref(o) for o in objs]
|
||||
self.pool.map(identity, objs)
|
||||
|
||||
del objs
|
||||
self.assertEqual(set(wr() for wr in refs), {None})
|
||||
# With a process pool, copies of the objects are returned, check
|
||||
# they were released too.
|
||||
self.assertEqual(CountedObject.n_instances, 0)
|
||||
|
||||
|
||||
def raising():
|
||||
raise KeyError("key")
|
||||
|
|
|
@ -46,6 +46,9 @@ Extension Modules
|
|||
Library
|
||||
-------
|
||||
|
||||
- bpo-29861: Release references to tasks, their arguments and their results
|
||||
as soon as they are finished in multiprocessing.Pool.
|
||||
|
||||
- bpo-29884: faulthandler: Restore the old sigaltstack during teardown.
|
||||
Patch by Christophe Zeitouny.
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue