【问题标题】:Python 3: Termination of threads in multiprocessing ThreadPool not workingPython 3:多处理线程池中的线程终止不起作用
【发布时间】:2017-10-27 23:14:58
【问题描述】:

我正在使用 Ubuntu 16.04.2 LTS 和 Python 3.5.2。 我有一个来自multiprocessingThreadPool 正在做一些工作。 现在我想在工作时终止这个池。

使用ThreadPool.terminate() 无法按预期工作。 运行以下示例时,worker 永远不会停止工作,并且程序永远不会超过 ThreadPool.join() 调用。

import time
from multiprocessing.pool import ThreadPool

def task():
    try:
        while True:
            print("Working")
            time.sleep(1)
    except: # Unsuccessful attempt. :(
        print("Working, stopping now")

thread_pool = ThreadPool(processes=1)

thread_pool.apply_async(task)
time.sleep(1) # Make sure the task is actually started.

print("Terminating")
thread_pool.terminate()
print("Termination: Initiated")
thread_pool.join() # Does not return.
print("Termination: Done")

我做错了什么?

【问题讨论】:

    标签: python multithreading python-3.x python-multiprocessing python-multithreading


    【解决方案1】:

    您特别要求ThreadPool 而不是Pool。这意味着multiprocessing 代码将创建一个本地线程(在您自己的进程中),而不是创建一个新进程。

    ThreadPool 实例不能被突然终止,因为没有为此定义的机制(与系统可以调用os.kill 的进程相比)。在您的代码中,.terminate 指令最终被忽略。事实上,它设置了一个标志,池实例将在任务返回时检查,但您的任务永远不会返回。我们可以通过修订版看到这一点:

    import argparse
    import sys
    import time
    
    from multiprocessing.pool import Pool, ThreadPool
    
    def task(arg):
        for i in range(3):
            print("Working on", arg, "with i =", i)
            time.sleep(1)
    
    def main():
        parser = argparse.ArgumentParser()
        parser.add_argument('--delay', default=1, type=float)
        args = parser.parse_args()
    
        thread_pool = ThreadPool(processes=1)
    
        thread_pool.apply_async(task, (0,))
        thread_pool.apply_async(task, (1,))
        time.sleep(args.delay)
    
        print("Terminating")
        thread_pool.terminate()
        print("Termination: Initiated")
        thread_pool.join() # Does not return.
        print("Termination: Done")
    
    if __name__ == '__main__':
        try:
            sys.exit(main())
        except KeyboardInterrupt:
            sys.exit('\nInterrupted')
    

    不带参数运行时会这样做:

    $ python3 tp.py
    Working on 0 with i = 0
    Working on 0 with i = 1
    Terminating
    Termination: Initiated
    Working on 0 with i = 2
    Termination: Done
    

    当使用--delay 5 运行时:

    $ python3 tp.py --delay 5
    Working on 0 with i = 0
    Working on 0 with i = 1
    Working on 0 with i = 2
    Working on 1 with i = 0
    Working on 1 with i = 1
    Terminating
    Working on 1 with i = 2
    Termination: Initiated
    Termination: Done
    

    或者,如果您只使用Pool 而不是ThreadPool,您将获得一个真实的进程,并且可以随时在其上使用.terminate(以通常关于搞砸通信队列的警告为模)。

    【讨论】:

    • 谢谢。我确实知道使用进程而不是线程的实际多处理实现,但我需要为我的应用程序使用线程。但是,我不知道ThreadPool.terminate()的实现其实是这样的。是否有任何替代 ThreadPool 的替代方法,我可以使用它而无需自己实现终止通信功能(并且可能对于每一个任务)?当然,必须做一些事情,比如在任务中捕获异常仍然可以。
    • 如果您的级别低于 Python 提供的级别,您可以向特定线程发送信号。该机制(显然)取决于机器。在某些系统(肯定是 FreeBSD)线程信号处理中也存在各种错误,这些错误可能在您的 Python 中有解决方法,可能会进一步干扰,因此您必须进行试验以确保它在您的系统上工作。可移植的方法是设置一个共享的“停止时间!”变量并在您的任务中定期检查它。
    猜你喜欢
    • 1970-01-01
    • 2023-02-20
    • 2019-01-29
    • 2019-06-25
    • 2023-03-18
    • 1970-01-01
    • 2019-04-06
    • 1970-01-01
    • 2020-09-13
    相关资源
    最近更新 更多