来自https://docs.python.org/3/library/concurrent.futures.html#concurrent.futures.Executor.map
如果函数调用引发异常,则将引发该异常 从迭代器中获取其值时。
以下片段仅胜过第一个片段(片段:1),然后停止。这是否与上述说法相抵触?我希望以下内容可以打印出循环中的所有异常。
def test_func(val):
raise Exception(val)
with concurrent.futures.ThreadPoolExecutor(max_workers=5) as executor:
for r in executor.map(test_func,[1,2,3,4,5]):
try:
print r
except Exception as exc:
print 'generated an exception: %s' % (exc)
答案 0 :(得分:2)
如上所述,不幸的是executor.map的API受限制,只能让您获得第一个异常。另外,遍历结果时,您只会获得直到第一个异常的值。
要回答您的问题,如果您不想使用其他库,则可以展开地图并手动应用每个功能:
future_list = []
with concurrent.futures.ThreadPoolExecutor() as executor:
for arg in range(10):
future = executor.submit(test_func, arg)
future_list.append(future)
for future in future_list:
try:
print(future.result())
except Exception as e:
print(e)
这使您可以分别处理每个将来。
答案 1 :(得分:1)
map
方法返回一个生成器,该生成器允许在准备好之后迭代结果。
不幸的是,发生异常后无法恢复生成器。来自PEP 255。
如果生成器函数引发或通过了未处理的异常(包括但不限于StopIteration),则该异常将以通常的方式传递给调用方,并随后尝试恢复生成器函数提高StopIteration。换句话说,未处理的异常会终止生成器的使用寿命。
答案 2 :(得分:1)
Ehsan的解决方案很好,但是完成结果而不是等待列表中的顺序项完成可能会稍微更有效率。这是来自library docs的示例。
public void showAvailability(MouseEvent event) {
selected = groupsTable.getSelectionModel().getSelectedItem();
boolean checkAvailability = checkSpaceInGroup(selected);
if(checkAvailability){
availabilityStatus.setText("Space in Group");
availabilityPane.setStyle("-fx-background-color: #" + "388e3c ");
}
else{
availabilityStatus.setText("NO SPACE");
availabilityPane.setStyle("-fx-background-color: #" + "ffcdd2 ");
}
}
答案 3 :(得分:1)
由于其他人给出了很好的答案,我想指出从问题中捕获异常的方法是错误的。以下代码段:
class ExceptionA(Exception):
pass
def test_func(val):
raise ExceptionA(val)
with concurrent.futures.ThreadPoolExecutor(max_workers=5) as executor:
try:
for r in executor.map(test_func, [1, 2, 3, 4, 5]):
try:
print(r)
except ExceptionA as exc:
print(f'Catch inside: {exc}')
except ExceptionA as exc:
print(f'Catch outside: {exc}')
给出输出 Catch outside: 1
。
python 文档如下:
<块引用>如果 func 调用引发异常,则将引发该异常 当它的值从迭代器中检索出来时。
这意味着如果你想捕获异常,你需要在循环外捕获它,因为值是在循环内检索的。