|
@@ -38,17 +38,48 @@ def reap_process(pid):
|
|
|
raise
|
|
|
return is_dead
|
|
|
|
|
|
+
|
|
|
+def process_is_dead(process):
|
|
|
+ # Make sure PID is an integer (no idea why this happens).
|
|
|
+ try:
|
|
|
+ int(process.pid)
|
|
|
+ except (TypeError, ValueError):
|
|
|
+ return True
|
|
|
+
|
|
|
+ # Try to see if the process is actually running,
|
|
|
+ # and reap zombie proceses while we're at it.
|
|
|
+
|
|
|
+ if reap_process(process.pid):
|
|
|
+ return True
|
|
|
+
|
|
|
+ # Then try to ping the process using its pipe.
|
|
|
+ try:
|
|
|
+ proc_is_alive = process.is_alive()
|
|
|
+ except OSError:
|
|
|
+ return True
|
|
|
+ else:
|
|
|
+ return not proc_is_alive
|
|
|
+
|
|
|
|
|
|
class DynamicPool(Pool):
|
|
|
"""Version of :class:`multiprocessing.Pool` that can dynamically grow
|
|
|
in size."""
|
|
|
|
|
|
def __init__(self, processes=None, initializer=None, initargs=()):
|
|
|
+
|
|
|
+ if processes is None:
|
|
|
+ try:
|
|
|
+ processes = cpu_count()
|
|
|
+ except NotImplementedError:
|
|
|
+ processes = 1
|
|
|
+
|
|
|
super(DynamicPool, self).__init__(processes=processes,
|
|
|
initializer=initializer,
|
|
|
initargs=initargs)
|
|
|
self._initializer = initializer
|
|
|
self._initargs = initargs
|
|
|
+ self._size = processes
|
|
|
+ self.logger = multiprocessing.get_logger()
|
|
|
|
|
|
def add_worker(self):
|
|
|
"""Add another worker to the pool."""
|
|
@@ -65,44 +96,26 @@ class DynamicPool(Pool):
|
|
|
[self.add_worker() for i in range(size)]
|
|
|
|
|
|
def is_dead(self, process):
|
|
|
- # Make sure PID is an integer (no idea why this happens).
|
|
|
- try:
|
|
|
- int(process.pid)
|
|
|
- except (TypeError, ValueError):
|
|
|
+ if process_is_dead(process):
|
|
|
+ self.logger.info("DynamicPool: Found dead process (PID: %s)" % (
|
|
|
+ process.pid))
|
|
|
return True
|
|
|
+ return False
|
|
|
|
|
|
- # Try to see if the process is actually running,
|
|
|
- # and reap zombie proceses while we're at it.
|
|
|
-
|
|
|
- if reap_process(process.pid):
|
|
|
- return True
|
|
|
-
|
|
|
- # Then try to ping the process using its pipe.
|
|
|
- try:
|
|
|
- proc_is_alive = process.is_alive()
|
|
|
- except OSError:
|
|
|
- return True
|
|
|
- else:
|
|
|
- return not proc_is_alive
|
|
|
-
|
|
|
- def replace_dead_workers(self):
|
|
|
- logger = multiprocessing.get_logger()
|
|
|
-
|
|
|
- new_pool = []
|
|
|
- dead_count = 0
|
|
|
+ def bring_out_the_dead(self):
|
|
|
+ dead = []
|
|
|
+ alive = []
|
|
|
for process in self._pool:
|
|
|
- if self.is_dead(process):
|
|
|
- logger.info("DynamicPool: Found dead process (PID: %s)" % (
|
|
|
- process.pid))
|
|
|
- dead_count += 1
|
|
|
- else:
|
|
|
- new_pool.append(process)
|
|
|
+ if process and process.pid:
|
|
|
+ if self.is_dead(process):
|
|
|
+ dead += [process]
|
|
|
+ else:
|
|
|
+ alive += [process]
|
|
|
+ return dead, alive
|
|
|
|
|
|
- if dead_count:
|
|
|
- self.grow(dead_count)
|
|
|
- self._pool = new_pool
|
|
|
-
|
|
|
- return dead_count
|
|
|
+ def replace_dead_workers(self):
|
|
|
+ dead, self._pool = self.bring_out_the_dead()
|
|
|
+ self.grow(self._size if len(dead) > self._size else len(dead))
|
|
|
|
|
|
|
|
|
class TaskPool(object):
|