Stop threaded mapping workers on cancellation and exceptions

This commit is contained in:
Andras Schmelczer 2026-10-27 19:58:12 +00:00
commit 38d222c825
2 changed files with 41 additions and 15 deletions

View file

@ -145,14 +145,14 @@ def threaded_parallel_map(
for i in range(config.concurrency) for i in range(config.concurrency)
] ]
for t in threads:
t.start()
def check_workers() -> None: def check_workers() -> None:
for thread in threads: for thread in threads:
if not thread.is_alive(): if not thread.is_alive():
raise WorkerException(f"Worker {thread.name} exited unexpectedly") raise WorkerException(f"Worker {thread.name} exited unexpectedly")
try:
for t in threads:
t.start()
yield from manage_communication( yield from manage_communication(
input_values=input_values, input_values=input_values,
chunk_size=config.chunk_size, chunk_size=config.chunk_size,
@ -162,6 +162,8 @@ def threaded_parallel_map(
ignore_exceptions=ignore_exceptions, ignore_exceptions=ignore_exceptions,
check_workers=check_workers, check_workers=check_workers,
) )
finally:
should_stop.set() should_stop.set()
for t in threads: for t in threads:
if t.ident is not None:
t.join(1) t.join(1)

View file

@ -1,7 +1,10 @@
import subprocess import subprocess
import sys import sys
import threading
from typing import Generator, cast
import pytest import pytest
from great_ai.utilities import WorkerException, threaded_parallel_map
@pytest.mark.parametrize("exception", ["SystemExit", "KeyboardInterrupt"]) @pytest.mark.parametrize("exception", ["SystemExit", "KeyboardInterrupt"])
@ -21,3 +24,24 @@ else:
[sys.executable, "-c", script], capture_output=True, text=True, timeout=10 [sys.executable, "-c", script], capture_output=True, text=True, timeout=10
) )
assert result.returncode == 0, result.stderr assert result.returncode == 0, result.stderr
@pytest.mark.parametrize("fail", [False, True])
def test_thread_workers_stop_after_close_or_error(fail: bool) -> None:
def predict(value: int) -> int:
if fail:
raise ValueError("failed")
return value
before = set(threading.enumerate())
iterator = cast(
Generator[int, None, None],
threaded_parallel_map(predict, range(100), concurrency=2, chunk_size=1),
)
if fail:
with pytest.raises(WorkerException):
next(iterator)
else:
assert next(iterator) == 0
iterator.close()
assert not set(threading.enumerate()) - before