-
-
Notifications
You must be signed in to change notification settings - Fork 30.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Executor.map and as_completed timeouts are able to deviate #79000
Comments
The map and as_completed functions can randomly timeout earlier or later due to NTP stepping the clock or something changing the time and/or date. Here's some code to reproduce the issue for map: import concurrent.futures
import time
with concurrent.futures.ThreadPoolExecutor() as executor:
list(executor.map(time.sleep, [29, 30], timeout=3000)) And similar code to reproduce it for as_completed: import concurrent.futures
import time
with concurrent.futures.ThreadPoolExecutor() as executor:
future1 = executor.submit(time.sleep, 29)
future2 = executor.submit(time.sleep, 30)
list(concurrent.futures.as_completed([future1, future2], timeout=3000)) It doesn't error normally, as it shouldn't, but if you move your clock an hour ahead within 30 seconds of running it you get this: Traceback (most recent call last):
File "<stdin>", line 2, in <module>
File "C:\Python\Python37\lib\concurrent\futures\_base.py", line 588, in result_iterator
yield fs.pop().result(end_time - time.time())
File "C:\Python\Python37\lib\concurrent\futures\_base.py", line 434, in result
raise TimeoutError()
concurrent.futures._base.TimeoutError Or this if you used the as_completed example: Traceback (most recent call last):
File "<stdin>", line 4, in <module>
File "C:\Python\Python37\lib\concurrent\futures\_base.py", line 238, in as_completed
len(pending), total_futures))
concurrent.futures._base.TimeoutError: 1 (of 2) futures unfinished The error stems from map and as_completed using time.time to calculate the duration for the timeout. The problem with time.time is that it's adjustable (i.e. it can skip around) which makes it unideal for comparing relative times. A solution would be to replace the time.time calls with either time.monotonic (preferable?) or time.perf_counter. |
Thanks for the report and PR. I can find a very similar issue where time.time was changed to time.monotonic across multiprocessing module by Victor for the same reason : bpo-34054. I don't know why it wasn't changed in concurrent.futures . Seems this was reported here : https://bugs.python.org/issue29733#msg289116. I am adding Victor and Antoine who might have thoughts on this. Feel free to remove yourself if it's not relevant. Thanks |
Sorry, please ignore the comment reference to https://bugs.python.org/issue29733#msg289116 . I misunderstood that it was about concurrent.futures using time.time but it turns out it was about the program using time.time as verifying the PR against the issue still has the timeout error. Thanks |
Oh, I missed the Lib/concurrent/futures/ directory when I tried to patch the whole stdlib to use monotonic clocks for timeouts :-( Thanks for the fix! |
Happy to help! I'm surprised it got merged so quickly, amazing response times all-around. |
Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.
Show more details
GitHub fields:
bugs.python.org fields:
The text was updated successfully, but these errors were encountered: