parallel.futures.ThreadPoolExecutor吞下异常(Python 3.6)

Let*_*t4U 1 python cpython windows-7-x64 python-multithreading python-3.x

我试图ThreadPoolExecutor在Windows 7上的Python 3.6中使用,似乎异常被忽略或停止了程序执行。示例代码:

#!/usr/bin/env python3

from time import sleep

from concurrent.futures import ThreadPoolExecutor

EXECUTOR = ThreadPoolExecutor(2)


def run_jobs():
    EXECUTOR.submit(some_long_task1)
    EXECUTOR.submit(some_long_task2, 'hello', 123)
    return 'Two jobs was launched in background!'


def some_long_task1():
    print("Task #1 started!")
    for i in range(10000000):
        j = i + 1
    1/0
    print("Task #1 is done!")


def some_long_task2(arg1, arg2):
    print("Task #2 started with args: %s %s!" % (arg1, arg2))
    for i in range(10000000):
        j = i + 1
    print("Task #2 is done!")


if __name__ == '__main__':
    run_jobs()
    while True:
        sleep(1)
Run Code Online (Sandbox Code Playgroud)

输出:

Task #1 started!
Task #2 started with args: hello 123!
Task #2 is done!
Run Code Online (Sandbox Code Playgroud)

它一直挂在那里,直到我用Ctrl+ 杀死它为止C

但是,当我1/0从中删除时some_long_task1,任务1顺利完成:

Task #1 started!
Task #2 started with args: hello 123!
Task #1 is done!
Task #2 is done!
Run Code Online (Sandbox Code Playgroud)

我需要捕获以ThreadPoolExecutor 某种方式运行的函数中引发的异常。

Python 3.6(Minconda),Windows 7 x64。

use*_*342 6

ThreadPoolExecutor.submit返回可用的将来对象,该对象代表计算结果。为了不忽略作业引发的异常,您需要实际访问此结果。首先,您可以更改run_job以返回创建的期货:

def run_jobs():
    fut1 = EXECUTOR.submit(some_long_task1)
    fut2 = EXECUTOR.submit(some_long_task2, 'hello', 123)
    return fut1, fut2
Run Code Online (Sandbox Code Playgroud)

然后,让顶级代码等待期货完成并访问其结果:

import concurrent.futures

if __name__ == '__main__':
    futures = run_jobs()
    concurrent.futures.wait(futures)
    for fut in futures:
        print(fut.result())
Run Code Online (Sandbox Code Playgroud)

result()在执行引发异常的将来进行调用会将异常传播到调用方。在这种情况下,ZeroDivisionError将在顶层提出。


aru*_*ska 5

您可以使用try语句处理异常。这就是您的some_long_task1方法的样子:

def some_long_task1():
    print("Task #1 started!")
    try:
        for i in range(10000000):
            j = i + 1
        1/0
    except Exception as exc:
        print('some_long_task1 generated an exception: {}'.format(exc))
    print("Task #1 is done!")
Run Code Online (Sandbox Code Playgroud)

在脚本中使用该方法时的输出:

Task #1 started!
Task #2 started with args: hello 123!
some_long_task1 generated an exception: integer division or modulo by zero
Task #1 is done!
Task #2 is done!
(the last while loop running...)
Run Code Online (Sandbox Code Playgroud)

  • 这并没有真正回答问题,因为问题的目标是捕获子线程的异常,并且从 Q 描述的性质来看,它似乎不理解 try: catch: 是这里的问题,因为 OP 专门询问捕获异常已经。 (7认同)