parallel.futures.Executor.map中的异常处理

时间:2018-06-27 21:04:38

标签: python concurrency concurrent.futures

来自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)

4 个答案:

答案 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。换句话说,未处理的异常会终止生成器的使用寿命。

还有pebble之类的其他库,它们允许在发生错误后继续迭代。检查文档中的examples

答案 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 调用引发异常,则将引发该异常 当它的值从迭代器中检索出来时。

这意味着如果你想捕获异常,你需要在循环外捕获它,因为值是在循环内检索的。