|
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