concurrent.futures.ThreadPoolExecutor 吞咽异常 (Python 3.6)
concurrent.futures.ThreadPoolExecutor swallowing exceptions (Python 3.6)
我正在尝试在 Windows 7 上使用 Python 3.6 中的 ThreadPoolExecutor
,似乎异常被默默地忽略或停止程序执行。示例代码:
#!/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)
输出:
Task #1 started!
Task #2 started with args: hello 123!
Task #2 is done!
它一直挂在那里,直到我用 Ctrl+C 杀死它。
但是,当我从 some_long_task1
中删除 1/0
时,任务 #1 顺利完成:
Task #1 started!
Task #2 started with args: hello 123!
Task #1 is done!
Task #2 is done!
我需要捕获 ThreadPoolExecutor
中函数 运行 中引发的异常 以某种方式 .
Python 3.6(明康达),Windows 7 x64。
您可以使用 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!")
在脚本中使用该方法时的输出:
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...)
ThreadPoolExecutor.submit
returns a future object 表示计算结果,一旦可用。为了不忽略作业引发的异常,您需要实际访问此结果。首先,您可以将创建的期货run_job
更改为return:
def run_jobs():
fut1 = EXECUTOR.submit(some_long_task1)
fut2 = EXECUTOR.submit(some_long_task2, 'hello', 123)
return fut1, fut2
然后,让 top-level 代码 wait 完成期货,并访问它们的结果:
import concurrent.futures
if __name__ == '__main__':
futures = run_jobs()
concurrent.futures.wait(futures)
for fut in futures:
print(fut.result())
在执行引发异常的未来上调用 result()
会将异常传播给调用者。在这种情况下,ZeroDivisionError
将在 top-level 处引发。
如前面的答案所示,有两种方法可以捕获 ThreadPoolExecutor
的异常 - 检查 future
中的异常或记录它们。这完全取决于一个人想要处理潜在的异常。一般来说,我的经验法则包括:
- 如果我只想记录错误,包括跟踪堆栈。
log.exception
是更好的选择。它需要添加额外的逻辑来通过future.exception()
. 记录相同数量的信息
- 如果代码需要在主线程中对不同的异常进行不同的处理。检查
future
的状态是可行的方法。此外,您可能会发现函数 as_completed 在这种情况下也很有用。
我正在尝试在 Windows 7 上使用 Python 3.6 中的 ThreadPoolExecutor
,似乎异常被默默地忽略或停止程序执行。示例代码:
#!/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)
输出:
Task #1 started!
Task #2 started with args: hello 123!
Task #2 is done!
它一直挂在那里,直到我用 Ctrl+C 杀死它。
但是,当我从 some_long_task1
中删除 1/0
时,任务 #1 顺利完成:
Task #1 started!
Task #2 started with args: hello 123!
Task #1 is done!
Task #2 is done!
我需要捕获 ThreadPoolExecutor
中函数 运行 中引发的异常 以某种方式 .
Python 3.6(明康达),Windows 7 x64。
您可以使用 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!")
在脚本中使用该方法时的输出:
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...)
ThreadPoolExecutor.submit
returns a future object 表示计算结果,一旦可用。为了不忽略作业引发的异常,您需要实际访问此结果。首先,您可以将创建的期货run_job
更改为return:
def run_jobs():
fut1 = EXECUTOR.submit(some_long_task1)
fut2 = EXECUTOR.submit(some_long_task2, 'hello', 123)
return fut1, fut2
然后,让 top-level 代码 wait 完成期货,并访问它们的结果:
import concurrent.futures
if __name__ == '__main__':
futures = run_jobs()
concurrent.futures.wait(futures)
for fut in futures:
print(fut.result())
在执行引发异常的未来上调用 result()
会将异常传播给调用者。在这种情况下,ZeroDivisionError
将在 top-level 处引发。
如前面的答案所示,有两种方法可以捕获 ThreadPoolExecutor
的异常 - 检查 future
中的异常或记录它们。这完全取决于一个人想要处理潜在的异常。一般来说,我的经验法则包括:
- 如果我只想记录错误,包括跟踪堆栈。
log.exception
是更好的选择。它需要添加额外的逻辑来通过future.exception()
. 记录相同数量的信息
- 如果代码需要在主线程中对不同的异常进行不同的处理。检查
future
的状态是可行的方法。此外,您可能会发现函数 as_completed 在这种情况下也很有用。