|
11 | 11 |
|
12 | 12 | # Import packages
|
13 | 13 | import os
|
| 14 | +import multiprocessing as mp |
14 | 15 | from multiprocessing import Pool, cpu_count, pool
|
15 | 16 | from traceback import format_exception
|
16 | 17 | import sys
|
@@ -73,24 +74,65 @@ def run_node(node, updatehash, taskid):
|
73 | 74 | # Return the result dictionary
|
74 | 75 | return result
|
75 | 76 |
|
| 77 | +# Pythons 2.7, 3.4-3.7.0, and 3.7.1 have three different implementations of |
| 78 | +# pool.Pool().Process(), and the type of the result varies based on the default |
| 79 | +# multiprocessing context, so we need to dynamically patch the daemon property |
| 80 | +class NonDaemonMixin(object): |
| 81 | + @property |
| 82 | + def daemon(self): |
| 83 | + return False |
| 84 | + |
| 85 | + @daemon.setter |
| 86 | + def daemon(self, val): |
| 87 | + pass |
76 | 88 |
|
77 |
| -class NonDaemonPool(pool.Pool): |
78 |
| - """A process pool with non-daemon processes. |
79 |
| - """ |
80 |
| - def Process(self, *args, **kwds): |
81 |
| - proc = super(NonDaemonPool, self).Process(*args, **kwds) |
82 |
| - |
83 |
| - class NonDaemonProcess(proc.__class__): |
84 |
| - """Monkey-patch process to ensure it is never daemonized""" |
85 |
| - @property |
86 |
| - def daemon(self): |
87 |
| - return False |
88 |
| - |
89 |
| - @daemon.setter |
90 |
| - def daemon(self, val): |
91 |
| - pass |
92 |
| - proc.__class__ = NonDaemonProcess |
93 |
| - return proc |
| 89 | +try: |
| 90 | + from multiprocessing import context |
| 91 | + # Exists on all platforms |
| 92 | + class NonDaemonSpawnProcess(NonDaemonMixin, context.SpawnProcess): |
| 93 | + pass |
| 94 | + class NonDaemonSpawnContext(context.SpawnContext): |
| 95 | + Process = NonDaemonSpawnProcess |
| 96 | + _nondaemon_context_mapper = { |
| 97 | + 'spawn': NonDaemonSpawnContext() |
| 98 | + } |
| 99 | + |
| 100 | + # POSIX only |
| 101 | + try: |
| 102 | + class NonDaemonForkProcess(NonDaemonMixin, context.ForkProcess): |
| 103 | + pass |
| 104 | + class NonDaemonForkContext(context.ForkContext): |
| 105 | + Process = NonDaemonForkProcess |
| 106 | + _nondaemon_context_mapper['fork'] = NonDaemonForkContext() |
| 107 | + except AttributeError: |
| 108 | + pass |
| 109 | + # POSIX only |
| 110 | + try: |
| 111 | + class NonDaemonForkServerProcess(NonDaemonMixin, context.ForkServerProcess): |
| 112 | + pass |
| 113 | + class NonDaemonForkServerContext(context.ForkServerContext): |
| 114 | + Process = NonDaemonForkServerProcess |
| 115 | + _nondaemon_context_mapper['forkserver'] = NonDaemonForkServerContext() |
| 116 | + except AttributeError: |
| 117 | + pass |
| 118 | + |
| 119 | + class NonDaemonPool(pool.Pool): |
| 120 | + def __init__(self, processes=None, initializer=None, initargs=(), |
| 121 | + maxtasksperchild=None, context=None): |
| 122 | + if context is None: |
| 123 | + context = mp.get_context() |
| 124 | + context = _nondaemon_context_mapper[context._name] |
| 125 | + super(NonDaemonPool, self).__init__(processes=processes, |
| 126 | + initializer=initializer, |
| 127 | + initargs=initargs, |
| 128 | + maxtasksperchild=maxtasksperchild, |
| 129 | + context=context) |
| 130 | + |
| 131 | +except ImportError: |
| 132 | + class NonDaemonProcess(NonDaemonMixin, mp.Process): |
| 133 | + pass |
| 134 | + class NonDaemonPool(pool.Pool): |
| 135 | + Process = NonDaemonProcess |
94 | 136 |
|
95 | 137 |
|
96 | 138 | class LegacyMultiProcPlugin(DistributedPluginBase):
|
|
0 commit comments