Search code examples
pythonconcurrencyconcurrent.futures

Exception handling in concurrent.futures.Executor.map


From https://docs.python.org/3/library/concurrent.futures.html#concurrent.futures.Executor.map

If a func call raises an exception, then that exception will be raised when its value is retrieved from the iterator.

The following snippet only outputs the first exception (Exception: 1), and stops. Does this contradict the above statement? I expect the following to print out all exceptions in the loop.

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)


Solution

  • The map method returns a generator which allows to iterate through the results once ready.

    Unfortunately, it is not possible to resume a generator after an exception occurs. From PEP 255.

    If an unhandled exception-- including, but not limited to, StopIteration --is raised by, or passes through, a generator function, then the exception is passed on to the caller in the usual way, and subsequent attempts to resume the generator function raise StopIteration. In other words, an unhandled exception terminates a generator's useful life.

    There are other libraries such as pebble which allow to continue the iteration after an error occurs. Check the examples in the documentation.