-
-
Notifications
You must be signed in to change notification settings - Fork 32.4k
bpo-38267: Add thread timeout parameter to loop.shutdown_default_executor()
#16360
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
Changes from 14 commits
700cf86
1e7794b
a262c45
b1bb810
8a4c30c
ebc1b99
5b90766
f189f04
16921a1
b678818
e332257
7f8428b
577b2b2
b673080
926de3f
f7c623c
169d2d4
f0dde2d
b7c0608
1e95afb
2b1f35d
e549996
8a5121c
4264c04
e9a0f19
d9c2e37
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,12 +5,16 @@ | |
from . import tasks | ||
|
||
|
||
# Default timeout for joining each thread in `shutdown_default_executor()` | ||
THREAD_JOIN_TIMEOUT = 300 | ||
|
||
|
||
def run(main, *, debug=False): | ||
"""Run a coroutine. | ||
|
||
This function runs the passed coroutine, taking care of | ||
managing the asyncio event loop and finalizing asynchronous | ||
generators. | ||
managing the asyncio event loop, finalizing asynchronous | ||
generators, and closing the threadpool. | ||
|
||
This function cannot be called when another asyncio event loop is | ||
running in the same thread. | ||
|
@@ -21,6 +25,10 @@ def run(main, *, debug=False): | |
It should be used as a main entry point for asyncio programs, and should | ||
ideally only be called once. | ||
|
||
Each thread within the threadpool is given a timeout duration of 5 | ||
minutes. If the thread hasn't finishing joining within that duration, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @1st1 While writing the documentation, I was thinking that @asvetlov's suggestion to add timeout as parameter for Do you think it might be useful to give users the option to adjust the timeout duration by adding a timeout parameter to There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think that adding knobs is only justified when there's request for that from users. In this particular case it's a bit tricky. The way I think about it is that it's easy to implement whatever timeout is necessary with the following pattern: asyncio.run(main())
# versus
async def runner():
try:
return await main()
finally:
loop = asyncio.get_running_loop()
await loop.shutdown_default_executor(3600)
asyncio.run(runner()) The argument for this pattern is that in more or less advanced asyncio applications there's always a "runner()" like in the above. It usually sets up signal handlers, manages global state, etc. Long story short, I'd go with this design and learn from our users if we need to make it configurable. This is just my opinion on this and I'd love to hear what @asvetlov thinks about it. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Ah, I actually hadn't thought as much about how relatively simple it would be for the users to create their own runner. I wonder if it would be worthwhile to document this pattern somewhere in
Yeah 5 minutes seems reasonable for most purposes. If it's an issue, we can easily adjust it by modifying the constant.
Good point. It might be a better idea to leave out the parameter initially and then add it in later if the users request it. It would be easy to add the new parameter to the API for
Personally I have no issue with either of the options, I think both of them would be viable. After reading your latest response, I'm leaning more in favor of keeping the current iteration though. The more I've been involved with API design, I've increasingly come to realize that there's frequently some degree of disconnect between what the users actually want and what the developers think the users want. It can definitely be worthwhile to start with a minimalist approach and add features based on user feedback, rather than making assumptions. Making too many assumptions can easily lead to feature bloat. |
||
the lock is released and the thread is terminated. | ||
|
||
Example: | ||
|
||
async def main(): | ||
|
@@ -45,7 +53,8 @@ async def main(): | |
try: | ||
_cancel_all_tasks(loop) | ||
loop.run_until_complete(loop.shutdown_asyncgens()) | ||
loop.run_until_complete(loop.shutdown_default_executor()) | ||
loop.run_until_complete( | ||
loop.shutdown_default_executor(timeout=THREAD_JOIN_TIMEOUT)) | ||
finally: | ||
events.set_event_loop(None) | ||
loop.close() | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
Add *timeout* parameter to :meth:`asyncio.loop.shutdown_default_executor`. |
Uh oh!
There was an error while loading. Please reload this page.