According to the docs:
If the call hasn’t yet completed then this method will wait up to timeout seconds. If the call hasn’t completed in timeout seconds, then a TimeoutError will be raised.
But clearly this is a False statement and doesn't represent the actual behavior:
from concurrent.futures import ThreadPoolExecutor, as_completed
from time import sleep
def my_worker(sleep_time, expected_timeout):
sleep(sleep_time)
print(f'slept for {sleep_time} | expected timeout: {expected_timeout}')
if __name__ == '__main__':
timeout = 1
with ThreadPoolExecutor(2) as executor:
futures = [executor.submit(my_worker, 3, timeout)]
for future in as_completed(futures):
future.result(timeout=timeout)
which results in:
slept for 3 | expected timeout: 1
There are other questions addressing a variation of the same issue with concurrent.futures
objects, but none provide any clarification of the timeout
argument in Future.result
.
Even the timeout
argument in concurrent.futures.as_completed
mentioned in the other questions is not working as expected. According to the docs:
The returned iterator raises a TimeoutError if next() is called and the result isn’t available after timeout seconds from the original call to as_completed(). timeout can be an int or float.
This sets me to expect a timeout exception is to be raised after whatever timeout
is specified of as_completed
call, disregarding how many tasks are pending. This also doesn't work as expected:
timeout = 1
with ThreadPoolExecutor(2) as executor:
futures = [executor.submit(my_worker, 3, timeout) for _ in range(5)]
for future in as_completed(futures, timeout): # should timeout after one second
future.result()
What actually happens: as_completed
ignores the timeout and awaits all tasks to finish before raising an error:
slept for 3 | expected timeout: 1
slept for 3 | expected timeout: 1
slept for 3 | expected timeout: 1
slept for 3 | expected timeout: 1
slept for 3 | expected timeout: 1
Traceback (most recent call last):
File "my_file.py", line 16, in <module>
completed.__next__()
File "/usr/local/Cellar/python@3.11/3.11.3/Frameworks/Python.framework/Versions/3.11/lib/python3.11/concurrent/futures/_base.py", line 239, in as_completed
raise TimeoutError(
TimeoutError: 5 (of 5) futures unfinished
Even the error message indicating that 5/5 tasks failed to complete is not true, otherwise these finished - timeout prompts wouldn't have shown.