ThreadPoolExecutor中的工作进程并不是真正的守护进程 [英] The workers in ThreadPoolExecutor is not really daemon

查看:0
本文介绍了ThreadPoolExecutor中的工作进程并不是真正的守护进程的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我搞不懂的是,虽然ThreadPoolExecutor使用守护进程工作器,但即使主线程退出,它们仍然会运行。

我可以在python3.6.4中提供一个最小的例子:

import concurrent.futures
import time


def fn():
    while True:
        time.sleep(5)
        print("Hello")


thread_pool = concurrent.futures.ThreadPoolExecutor()
thread_pool.submit(fn)
while True:
    time.sleep(1)
    print("Wow")

主线程和辅助线程都是无限循环。因此,如果我使用KeyboardInterrupt来终止主线程,我预计整个程序也将终止。但实际上工作线程仍在运行,即使它是守护程序线程。

ThreadPoolExecutor的源代码确认工作线程是守护进程线程:

t = threading.Thread(target=_worker,
                     args=(weakref.ref(self, weakref_cb),
                           self._work_queue))
t.daemon = True
t.start()
self._threads.add(t)

此外,如果我手动创建守护程序线程,它的工作方式就像符咒一样:

from threading import Thread
import time


def fn():
    while True:
        time.sleep(5)
        print("Hello")


thread = Thread(target=fn)
thread.daemon = True
thread.start()
while True:
    time.sleep(1)
    print("Wow")

所以我真的搞不懂这种奇怪的行为。

推荐答案

突然...我找到原因了。根据ThreadPoolExecutor的更多源代码:

# Workers are created as daemon threads. This is done to allow the interpreter
# to exit when there are still idle threads in a ThreadPoolExecutor's thread
# pool (i.e. shutdown() was not called). However, allowing workers to die with
# the interpreter has two undesirable properties:
#   - The workers would still be running during interpreter shutdown,
#     meaning that they would fail in unpredictable ways.
#   - The workers could be killed while evaluating a work item, which could
#     be bad if the callable being evaluated has external side-effects e.g.
#     writing to a file.
#
# To work around this problem, an exit handler is installed which tells the
# workers to exit when their work queues are empty and then waits until the
# threads finish.

_threads_queues = weakref.WeakKeyDictionary()
_shutdown = False

def _python_exit():
    global _shutdown
    _shutdown = True
    items = list(_threads_queues.items())
    for t, q in items:
        q.put(None)
    for t, q in items:
        t.join()

atexit.register(_python_exit)

有一个退出处理程序将加入所有未完成的工作...

这篇关于ThreadPoolExecutor中的工作进程并不是真正的守护进程的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆