mirror of
https://github.com/python/cpython.git
synced 2025-09-01 22:47:59 +00:00
Issue #23992: multiprocessing: make MapResult not fail-fast upon exception.
This commit is contained in:
parent
eaf8ebc139
commit
78f55ffc63
3 changed files with 38 additions and 8 deletions
|
@ -638,18 +638,22 @@ class MapResult(ApplyResult):
|
|||
self._number_left = length//chunksize + bool(length % chunksize)
|
||||
|
||||
def _set(self, i, success_result):
|
||||
success, result = success_result
|
||||
if success:
|
||||
self._value[i*self._chunksize:(i+1)*self._chunksize] = result
|
||||
self._number_left -= 1
|
||||
success, result = success_result
|
||||
if success and self._success:
|
||||
self._value[i*self._chunksize:(i+1)*self._chunksize] = result
|
||||
if self._number_left == 0:
|
||||
if self._callback:
|
||||
self._callback(self._value)
|
||||
del self._cache[self._job]
|
||||
self._event.set()
|
||||
else:
|
||||
if not success and self._success:
|
||||
# only store first exception
|
||||
self._success = False
|
||||
self._value = result
|
||||
if self._number_left == 0:
|
||||
# only consider the result ready once all jobs are done
|
||||
if self._error_callback:
|
||||
self._error_callback(self._value)
|
||||
del self._cache[self._job]
|
||||
|
|
|
@ -1660,6 +1660,10 @@ def sqr(x, wait=0.0):
|
|||
def mul(x, y):
|
||||
return x*y
|
||||
|
||||
def raise_large_valuerror(wait):
|
||||
time.sleep(wait)
|
||||
raise ValueError("x" * 1024**2)
|
||||
|
||||
class SayWhenError(ValueError): pass
|
||||
|
||||
def exception_throwing_generator(total, when):
|
||||
|
@ -1895,6 +1899,26 @@ class _TestPool(BaseTestCase):
|
|||
with self.assertRaises(RuntimeError):
|
||||
p.apply(self._test_wrapped_exception)
|
||||
|
||||
def test_map_no_failfast(self):
|
||||
# Issue #23992: the fail-fast behaviour when an exception is raised
|
||||
# during map() would make Pool.join() deadlock, because a worker
|
||||
# process would fill the result queue (after the result handler thread
|
||||
# terminated, hence not draining it anymore).
|
||||
|
||||
t_start = time.time()
|
||||
|
||||
with self.assertRaises(ValueError):
|
||||
with self.Pool(2) as p:
|
||||
try:
|
||||
p.map(raise_large_valuerror, [0, 1])
|
||||
finally:
|
||||
time.sleep(0.5)
|
||||
p.close()
|
||||
p.join()
|
||||
|
||||
# check that we indeed waited for all jobs
|
||||
self.assertGreater(time.time() - t_start, 0.9)
|
||||
|
||||
|
||||
def raising():
|
||||
raise KeyError("key")
|
||||
|
|
|
@ -179,6 +179,8 @@ Core and Builtins
|
|||
Library
|
||||
-------
|
||||
|
||||
- Issue #23992: multiprocessing: make MapResult not fail-fast upon exception.
|
||||
|
||||
- Issue #26243: Support keyword arguments to zlib.compress(). Patch by Aviv
|
||||
Palivoda.
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue