@@ -131,6 +131,7 @@ def __init__(self, work_id, fn, args, kwargs):
131131 self .args = args
132132 self .kwargs = kwargs
133133
134+
134135def _get_chunks (* iterables , chunksize ):
135136 """ Iterates over zip()ed iterables in chunks. """
136137 it = zip (* iterables )
@@ -151,7 +152,7 @@ def _process_chunk(fn, chunk):
151152 """
152153 return [fn (* args ) for args in chunk ]
153154
154- def _process_worker (call_queue , result_queue ):
155+ def _process_worker (call_queue , result_queue , initializer , initargs ):
155156 """Evaluates calls from call_queue and places the results in result_queue.
156157
157158 This worker is run in a separate process.
@@ -161,7 +162,17 @@ def _process_worker(call_queue, result_queue):
161162 evaluated by the worker.
162163 result_queue: A ctx.Queue of _ResultItems that will written
163164 to by the worker.
165+ initializer: A callable initializer, or None
166+ initargs: A tuple of args for the initializer
164167 """
168+ if initializer is not None :
169+ try :
170+ initializer (* initargs )
171+ except BaseException :
172+ _base .LOGGER .critical ('Exception in initializer:' , exc_info = True )
173+ # The parent will notice that the process stopped and
174+ # mark the pool broken
175+ return
165176 while True :
166177 call_item = call_queue .get (block = True )
167178 if call_item is None :
@@ -277,7 +288,9 @@ def shutdown_worker():
277288 # Mark the process pool broken so that submits fail right now.
278289 executor = executor_reference ()
279290 if executor is not None :
280- executor ._broken = True
291+ executor ._broken = ('A child process terminated '
292+ 'abruptly, the process pool is not '
293+ 'usable anymore' )
281294 executor ._shutdown_thread = True
282295 executor = None
283296 # All futures in flight must be marked failed
@@ -372,15 +385,16 @@ def _chain_from_iterable_of_lists(iterable):
372385 yield element .pop ()
373386
374387
375- class BrokenProcessPool (RuntimeError ):
388+ class BrokenProcessPool (_base . BrokenExecutor ):
376389 """
377390 Raised when a process in a ProcessPoolExecutor terminated abruptly
378391 while a future was in the running state.
379392 """
380393
381394
382395class ProcessPoolExecutor (_base .Executor ):
383- def __init__ (self , max_workers = None , mp_context = None ):
396+ def __init__ (self , max_workers = None , mp_context = None ,
397+ initializer = None , initargs = ()):
384398 """Initializes a new ProcessPoolExecutor instance.
385399
386400 Args:
@@ -389,6 +403,8 @@ def __init__(self, max_workers=None, mp_context=None):
389403 worker processes will be created as the machine has processors.
390404 mp_context: A multiprocessing context to launch the workers. This
391405 object should provide SimpleQueue, Queue and Process.
406+ initializer: An callable used to initialize worker processes.
407+ initargs: A tuple of arguments to pass to the initializer.
392408 """
393409 _check_system_limits ()
394410
@@ -403,6 +419,11 @@ def __init__(self, max_workers=None, mp_context=None):
403419 mp_context = mp .get_context ()
404420 self ._mp_context = mp_context
405421
422+ if initializer is not None and not callable (initializer ):
423+ raise TypeError ("initializer must be a callable" )
424+ self ._initializer = initializer
425+ self ._initargs = initargs
426+
406427 # Make the call queue slightly larger than the number of processes to
407428 # prevent the worker processes from idling. But don't make it too big
408429 # because futures in the call queue cannot be cancelled.
@@ -450,15 +471,16 @@ def _adjust_process_count(self):
450471 p = self ._mp_context .Process (
451472 target = _process_worker ,
452473 args = (self ._call_queue ,
453- self ._result_queue ))
474+ self ._result_queue ,
475+ self ._initializer ,
476+ self ._initargs ))
454477 p .start ()
455478 self ._processes [p .pid ] = p
456479
457480 def submit (self , fn , * args , ** kwargs ):
458481 with self ._shutdown_lock :
459482 if self ._broken :
460- raise BrokenProcessPool ('A child process terminated '
461- 'abruptly, the process pool is not usable anymore' )
483+ raise BrokenProcessPool (self ._broken )
462484 if self ._shutdown_thread :
463485 raise RuntimeError ('cannot schedule new futures after shutdown' )
464486
0 commit comments