|
@@ -592,7 +592,7 @@ class Pool(object):
|
|
|
w.start()
|
|
|
return w
|
|
|
|
|
|
- def _join_exited_workers(self, shutdown=False, lost_worker_timeout=10.0):
|
|
|
+ def _join_exited_workers(self, shutdown=False):
|
|
|
"""Cleanup after any worker processes which have exited due to
|
|
|
reaching their specified lifetime. Returns True if any workers were
|
|
|
cleaned up.
|
|
@@ -600,11 +600,12 @@ class Pool(object):
|
|
|
now = None
|
|
|
# The worker may have published a result before being terminated,
|
|
|
# but we have no way to accurately tell if it did. So we wait for
|
|
|
- # 10 seconds before we mark the job with WorkerLostError.
|
|
|
+ # _lost_worker_timeout seconds before we mark the job with
|
|
|
+ # WorkerLostError.
|
|
|
for job in [job for job in self._cache.values()
|
|
|
if not job.ready() and job._worker_lost]:
|
|
|
now = now or time.time()
|
|
|
- if now - job._worker_lost > lost_worker_timeout:
|
|
|
+ if now - job._worker_lost > job._lost_worker_timeout:
|
|
|
exc_info = None
|
|
|
try:
|
|
|
raise WorkerLostError("Worker exited prematurely.")
|
|
@@ -730,39 +731,44 @@ class Pool(object):
|
|
|
assert self._state == RUN
|
|
|
return self.map_async(func, iterable, chunksize).get()
|
|
|
|
|
|
- def imap(self, func, iterable, chunksize=1):
|
|
|
+ def imap(self, func, iterable, chunksize=1, lost_worker_timeout=10.0):
|
|
|
'''
|
|
|
Equivalent of `itertools.imap()` -- can be MUCH slower
|
|
|
than `Pool.map()`
|
|
|
'''
|
|
|
assert self._state == RUN
|
|
|
if chunksize == 1:
|
|
|
- result = IMapIterator(self._cache)
|
|
|
+ result = IMapIterator(self._cache,
|
|
|
+ lost_worker_timeout=lost_worker_timeout)
|
|
|
self._taskqueue.put((((result._job, i, func, (x,), {})
|
|
|
for i, x in enumerate(iterable)), result._set_length))
|
|
|
return result
|
|
|
else:
|
|
|
assert chunksize > 1
|
|
|
task_batches = Pool._get_tasks(func, iterable, chunksize)
|
|
|
- result = IMapIterator(self._cache)
|
|
|
+ result = IMapIterator(self._cache,
|
|
|
+ lost_worker_timeout=lost_worker_timeout)
|
|
|
self._taskqueue.put((((result._job, i, mapstar, (x,), {})
|
|
|
for i, x in enumerate(task_batches)), result._set_length))
|
|
|
return (item for chunk in result for item in chunk)
|
|
|
|
|
|
- def imap_unordered(self, func, iterable, chunksize=1):
|
|
|
+ def imap_unordered(self, func, iterable, chunksize=1,
|
|
|
+ lost_worker_timeout=10.0):
|
|
|
'''
|
|
|
Like `imap()` method but ordering of results is arbitrary
|
|
|
'''
|
|
|
assert self._state == RUN
|
|
|
if chunksize == 1:
|
|
|
- result = IMapUnorderedIterator(self._cache)
|
|
|
+ result = IMapUnorderedIterator(self._cache,
|
|
|
+ lost_worker_timeout=lost_worker_timeout)
|
|
|
self._taskqueue.put((((result._job, i, func, (x,), {})
|
|
|
for i, x in enumerate(iterable)), result._set_length))
|
|
|
return result
|
|
|
else:
|
|
|
assert chunksize > 1
|
|
|
task_batches = Pool._get_tasks(func, iterable, chunksize)
|
|
|
- result = IMapUnorderedIterator(self._cache)
|
|
|
+ result = IMapUnorderedIterator(self._cache,
|
|
|
+ lost_worker_timeout=lost_worker_timeout)
|
|
|
self._taskqueue.put((((result._job, i, mapstar, (x,), {})
|
|
|
for i, x in enumerate(task_batches)), result._set_length))
|
|
|
return (item for chunk in result for item in chunk)
|
|
@@ -939,7 +945,7 @@ class ApplyResult(object):
|
|
|
|
|
|
def __init__(self, cache, callback, accept_callback=None,
|
|
|
timeout_callback=None, error_callback=None, soft_timeout=None,
|
|
|
- timeout=None):
|
|
|
+ timeout=None, lost_worker_timeout=10.0):
|
|
|
self._mutex = threading.Lock()
|
|
|
self._cond = threading.Condition(threading.Lock())
|
|
|
self._job = job_counter.next()
|
|
@@ -951,6 +957,7 @@ class ApplyResult(object):
|
|
|
self._timeout_callback = timeout_callback
|
|
|
self._timeout = timeout
|
|
|
self._soft_timeout = soft_timeout
|
|
|
+ self._lost_worker_timeout = lost_worker_timeout
|
|
|
|
|
|
self._accepted = False
|
|
|
self._worker_pid = None
|
|
@@ -1094,15 +1101,19 @@ class MapResult(ApplyResult):
|
|
|
|
|
|
|
|
|
class IMapIterator(object):
|
|
|
+ _worker_lost = None
|
|
|
|
|
|
- def __init__(self, cache):
|
|
|
+ def __init__(self, cache, lost_worker_timeout=10.0):
|
|
|
self._cond = threading.Condition(threading.Lock())
|
|
|
self._job = job_counter.next()
|
|
|
self._cache = cache
|
|
|
self._items = collections.deque()
|
|
|
self._index = 0
|
|
|
self._length = None
|
|
|
+ self._ready = False
|
|
|
self._unsorted = {}
|
|
|
+ self._worker_pids = []
|
|
|
+ self._lost_worker_timeout = lost_worker_timeout
|
|
|
cache[self._job] = self
|
|
|
|
|
|
def __iter__(self):
|
|
@@ -1115,12 +1126,14 @@ class IMapIterator(object):
|
|
|
item = self._items.popleft()
|
|
|
except IndexError:
|
|
|
if self._index == self._length:
|
|
|
+ self._ready = True
|
|
|
raise StopIteration
|
|
|
self._cond.wait(timeout)
|
|
|
try:
|
|
|
item = self._items.popleft()
|
|
|
except IndexError:
|
|
|
if self._index == self._length:
|
|
|
+ self._ready = True
|
|
|
raise StopIteration
|
|
|
raise TimeoutError
|
|
|
finally:
|
|
@@ -1129,7 +1142,7 @@ class IMapIterator(object):
|
|
|
success, value = item
|
|
|
if success:
|
|
|
return value
|
|
|
- raise value
|
|
|
+ raise Exception(value)
|
|
|
|
|
|
__next__ = next # XXX
|
|
|
|
|
@@ -1148,6 +1161,7 @@ class IMapIterator(object):
|
|
|
self._unsorted[i] = obj
|
|
|
|
|
|
if self._index == self._length:
|
|
|
+ self._ready = True
|
|
|
del self._cache[self._job]
|
|
|
finally:
|
|
|
self._cond.release()
|
|
@@ -1157,11 +1171,21 @@ class IMapIterator(object):
|
|
|
try:
|
|
|
self._length = length
|
|
|
if self._index == self._length:
|
|
|
+ self._ready = True
|
|
|
self._cond.notify()
|
|
|
del self._cache[self._job]
|
|
|
finally:
|
|
|
self._cond.release()
|
|
|
|
|
|
+ def _ack(self, i, time_accepted, pid):
|
|
|
+ self._worker_pids.append(pid)
|
|
|
+
|
|
|
+ def ready(self):
|
|
|
+ return self._ready
|
|
|
+
|
|
|
+ def worker_pids(self):
|
|
|
+ return self._worker_pids
|
|
|
+
|
|
|
#
|
|
|
# Class whose instances are returned by `Pool.imap_unordered()`
|
|
|
#
|
|
@@ -1176,6 +1200,7 @@ class IMapUnorderedIterator(IMapIterator):
|
|
|
self._index += 1
|
|
|
self._cond.notify()
|
|
|
if self._index == self._length:
|
|
|
+ self._ready = True
|
|
|
del self._cache[self._job]
|
|
|
finally:
|
|
|
self._cond.release()
|