|
59 | 59 | import sys
|
60 | 60 | import traceback
|
61 | 61 |
|
62 |
| -# Workers are created as daemon threads and processes. This is done to allow the |
63 |
| -# interpreter to exit when there are still idle processes in a |
64 |
| -# ProcessPoolExecutor's process pool (i.e. shutdown() was not called). However, |
65 |
| -# allowing workers to die with the interpreter has two undesirable properties: |
66 |
| -# - The workers would still be running during interpreter shutdown, |
67 |
| -# meaning that they would fail in unpredictable ways. |
68 |
| -# - The workers could be killed while evaluating a work item, which could |
69 |
| -# be bad if the callable being evaluated has external side-effects e.g. |
70 |
| -# writing to a file. |
71 |
| -# |
72 |
| -# To work around this problem, an exit handler is installed which tells the |
73 |
| -# workers to exit when their work queues are empty and then waits until the |
74 |
| -# threads/processes finish. |
75 | 62 |
|
76 | 63 | _threads_wakeups = weakref.WeakKeyDictionary()
|
77 | 64 | _global_shutdown = False
|
@@ -107,6 +94,12 @@ def _python_exit():
|
107 | 94 | for t, _ in items:
|
108 | 95 | t.join()
|
109 | 96 |
|
| 97 | +# Register for `_python_exit()` to be called just before joining all |
| 98 | +# non-daemon threads. This is used instead of `atexit.register()` for |
| 99 | +# compatibility with subinterpreters, which no longer support daemon threads. |
| 100 | +# See bpo-39812 for context. |
| 101 | +threading._register_atexit(_python_exit) |
| 102 | + |
110 | 103 | # Controls how many more calls than processes will be queued in the call queue.
|
111 | 104 | # A smaller number will mean that processes spend more time idle waiting for
|
112 | 105 | # work while a larger number will make Future.cancel() succeed less frequently
|
@@ -306,9 +299,7 @@ def weakref_cb(_, thread_wakeup=self.thread_wakeup):
|
306 | 299 | # {5: <_WorkItem...>, 6: <_WorkItem...>, ...}
|
307 | 300 | self.pending_work_items = executor._pending_work_items
|
308 | 301 |
|
309 |
| - # Set this thread to be daemonized |
310 | 302 | super().__init__()
|
311 |
| - self.daemon = True |
312 | 303 |
|
313 | 304 | def run(self):
|
314 | 305 | # Main loop for the executor manager thread.
|
@@ -732,5 +723,3 @@ def shutdown(self, wait=True, *, cancel_futures=False):
|
732 | 723 | self._executor_manager_thread_wakeup = None
|
733 | 724 |
|
734 | 725 | shutdown.__doc__ = _base.Executor.shutdown.__doc__
|
735 |
| - |
736 |
| -atexit.register(_python_exit) |
0 commit comments