python / python/cpython

Cancel futures if concurrent.futures.Executor is used as a context manager and there is an exception?

Offen
#130,975 2 Kommentare 3 Reaktionen 1 zugewiesene Person Auf GitHub ansehen

@gpshead arbeitet bereits daran.

Seit 13.6.2026.

stdlib type-feature
Vorherrschende Sprache
Python
Sterne
77.2k
Forks
35.9k
PR-Merge-Kennzahlen
PR-Kennzahlen ausstehend

Beschreibung

I bumped into a bit of a rough edge related to how concurrent.futures.Executor instances behave when they're used as context managers and there is an exception raised from the with statement body.

I had some code like this (reduced to the bare minimum):

with concurrent.futures.ThreadPoolExecutor(max_workers=10) as executor:
    futures = {
        executor.submit(check_status, item): item
        for item in to_check
    }
    for index, future in enumerate(concurrent.futures.as_completed(futures)):
        print(f"{index}/{len(futures)} {future.result()}")

Now, as it happens check_status liked to raise an exception from time to time and this would be fine if the application stopped because of that but it kept going but in a weird way. What I saw was check_status kept producing logs but the print calls in the snippet above stopped being executed.

This is because of how Executor implements __exit__ – it waits for all pending futures to complete before propagating the exception:

    def __exit__(self, exc_type, exc_val, exc_tb):
        self.shutdown(wait=True)
        return False

No in my case I started with thousands of futures so it could take hours for the process to finally crash.

Since Python 3.9 the shutdown method has the cancel_futures parameter (implemented in https://github.com/python/cpython/pull/18057): https://docs.python.org/3.9/library/concurrent.futures.html#concurrent.futures.Executor.shutdown.

I'm proposing changing the behavior of the context manager __exit__ to cancel futures if there is an exception:

    def __exit__(self, exc_type, exc_val, exc_tb):
        self.shutdown(wait=True, cancel_futures=exc_val is not None)
        return False

This would allow the in-flight futures to finish but any further processing wouldn't happen and the exception would be reported in a (more) timely fashion.

cc @brianquinlan @pitrou as I saw you participate in the cancel_futures PR, if there's someone else I should ping here for visibility please let me know.

Beitragsleitfaden

Beitragsleitfaden öffnen

Erste Schritte

  1. Lies das ganze Issue und danach den Beitragsleitfaden des Projekts.
  2. Schreib ins Issue, dass du es übernimmst — das erspart doppelte Arbeit.
  3. Forke das Repository und arbeite in einem Branch.
  4. Öffne einen Pull Request, der die Issue-Nummer nennt.

Bewertung

Dieses Issue wurde noch nicht bewertet.

Neue Issues direkt in Ihr Postfach

Eine kurze Übersicht über anfängerfreundliche GitHub-Issues.