Skip to content

concurrent.futures: Executor.map cancels the remaining calls when the callable raises TimeoutError #155852

Description

@tonghuaroot

Bug report

gh-108518 documented that if a call raises, :meth:Executor.map no longer
cancels the remaining calls and iteration can continue. That holds for every
exception except :exc:TimeoutError, which still aborts and cancels the rest.

from concurrent.futures import ThreadPoolExecutor

def f(x):
    if x == 2:
        raise TimeoutError   # e.g. a socket.timeout from one network call
    return x

with ThreadPoolExecutor() as ex:
    it = ex.map(f, [1, 2, 3, 4])
    print(next(it))                         # 1
    try: next(it)                           # raises TimeoutError for x=2
    except TimeoutError: pass
    print(list(it))                         # [] -- 3 and 4 were cancelled

With any other exception (e.g. ValueError) the last line prints [3, 4].
socket.timeout and asyncio.TimeoutError are aliases of
:exc:TimeoutError, so a single timed-out call in a mapped batch silently
drops all remaining work. ProcessPoolExecutor is unaffected.

The cause is in _result_or_cancel: a TimeoutError from the callable is
indistinguishable by type from the map(timeout=...) wait timeout, so it is
re-raised instead of being returned like other exceptions.

Linked PRs

Metadata

Metadata

Assignees

No one assigned

    Labels

    3.16new features, bugs and security fixesstdlibStandard Library Python modules in the Lib/ directorytopic-multiprocessingtype-bugAn unexpected behavior, bug, or error

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions