Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/326.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python ThreadPoolExecutor中的worker并不是真正的守护进程_Python_Multithreading_Daemon_Concurrent.futures - Fatal编程技术网

Python ThreadPoolExecutor中的worker并不是真正的守护进程

Python ThreadPoolExecutor中的worker并不是真正的守护进程,python,multithreading,daemon,concurrent.futures,Python,Multithreading,Daemon,Concurrent.futures,我无法理解的是,尽管ThreadPoolExecutor使用守护进程工作程序,但即使主线程退出,它们仍将运行 我可以在python3.6.4中提供一个简单的示例: import concurrent.futures import time def fn(): while True: time.sleep(5) print("Hello") thread_pool = concurrent.futures.ThreadPoolExecutor() t

我无法理解的是,尽管
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)

有一个退出处理程序将连接所有未完成的工作人员…

以下是避免此问题的方法。糟糕的设计可以被另一个糟糕的设计打败。只有当人们真正知道工作人员不会损坏任何对象或文件时,才会编写
daemon=True

在我的例子中,我用一个worker创建了
TreadPoolExecutor
,在一次
submit
之后,我刚刚从队列中删除了新创建的线程,这样解释器就不会等到这个线程自行停止。请注意,工作线程是在
submit
之后创建的,而不是在
TreadPoolExecutor
初始化之后创建的

import concurrent.futures.thread
从concurrent.futures导入ThreadPoolExecutor
...
执行器=线程池执行器(最大工作线程数=1)
future=executor.submit(lambda:self.\u exec\u文件(args))
del concurrent.futures.thread.\u threads.\u队列[列表(执行器.\u线程)[0]]
它在Python3.8中工作,但在3.9+中可能不工作,因为此代码正在访问私有变量


查看工作代码

然后,如果它不能实现主要目的,那么
daemon=True
有什么好处?