Uh oh!
There was an error while loading. Please reload this page.
bpo-34037: Fix test_asyncio failure and add loop.shutdown_default_executor() - #15735
Conversation
There was a problem hiding this comment.
I'll fix the number of characters per line and add the appropriate Sphinx roles after I finish adding the documentation changes.
aeros
commented
Sep 9, 2019
Adding a |
vstinner
left a comment
There was a problem hiding this comment.
You have to update the documentation:
- Document the 2 new event loop methods, around https://docs.python.org/dev/library/asyncio-eventloop.html
- Document the behavior change in What's New in Python 3.9, around: https://docs.python.org/dev/whatsnew/3.9.html#changes-in-the-python-api
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
bedevere-bot
commented
Sep 9, 2019
A Python core developer has requested some changes be made to your pull request before we can consider merging it. If you could please address their requests along with any other requests in other reviews from core developers that would be appreciated. Once you have made the requested changes, please leave a comment on this pull request containing the phrase |
aeros
commented
Sep 9, 2019
Thanks for the feedback @vstinner.
Yep, I was definitely planning on doing so within this PR. I just wanted to make sure the implementation details were satisfactory first, so that I wouldn't have to add the documentation changes and then completely rewrite them from different specifications. I'll start working on that next. I appreciate that you specified the locations. I figured the documentation for the methods would be on asyncio event loop page, but I wasn't certain where to place the changes in What's New (or whether that should be done within this PR). This will be my first time adding an entry in there, as the majority of my contributions thus far have been PR reviews or documentation changes. I have to admit, adding my own What's New entry for 3.9 is both a little intimidating and exciting. (: |
There was a problem hiding this comment.
I still don't like this API and I'd suggest to implement it the other way around. We have a very similar problem with asynchronous generators -- closing them isn't an easy process and can be a lengthy blocking operation. The way we do that is via the loop.shutdown_asyncgens() method, that users are supposed to call manually before loop.close(). This is a low-level API, and the expectation is that asyncio.run() function would do that for you.
Therefore I propose the following:
Add a new
loop.shutdown_threadpool()method. Just like withshutdown_asyncgens()-- it would be invalid to callloop.run_in_executer()afterloop.shutdown_threadpool()is called.Make
asyncio.run()to call the newloop.shutdown_threadpool().
1st1
commented
Sep 9, 2019
@aeros167 Kyle, do you have time to work on this issue this week? |
aeros
commented
Sep 9, 2019
Yeah, I definitely should have time to work on it. Would you recommend making the changes directly to this PR or opening a separate one? I think your proposal would be far more robust and provide a significantly better user experience. But this change might be a decent fallback, mainly for the purpose of fixing the CI tests in case there are unforeseen complications with properly implementing the proposed I would be glad to help with working on implementing it though. I've been interested in becoming more involved with improving the CI tests and asyncio development in general, and I think this process will provide a great introduction to both. Thanks for the in-depth feedback. |
asvetlov
commented
Sep 9, 2019
I support @1st1 proposal: |
1st1
commented
Sep 9, 2019
Well, it's a bit too late to add new APIs in the 3.8 branch, no matter if they are public or private. I suggest to go ahead with the new idea so that we can fix the CI for the master branch. FWIW @vstinner suggested the |
My current plan:
defshutdown_default_executor(self, wait=True):
# Used by loop.run_in_executer() to check if the the executor has been terminatedself._executor_shutdown_called=Trueexecutor=self._default_executor# Nothing to shut down if there is no executorifexecutorisnotNone: self._default_executor=Noneexecutor.shutdown(wait) # alternatively, wait=wait, but that seems redundant
def_check_executor_shutdown(self):
ifself._executor_shutdown_called:
raiseRuntimeError("Executor has been shut down")
defclose(self):
...
self._closed=Trueself._ready.clear()
self._scheduled.clear()
# executor = self._default_executor# if executor is not None:# self._default_executor = None# executor.shutdown(wait=self._wait_executor_on_close)self.shutdown_default_executor() # default is TrueIn the above implementation, users could directly utilize If further customization is required (or there's issues with the tests timing out in the future), we could add an optional argument thread_timeout to
If the above is satisfactory, +1 this comment, otherwise let me know if anything is incorrect. Note: Several of the comments in the examples above are for the purpose of explaining my thought process, and would not be included in the PR. Particularly the inline comments. |
aeros
commented
Sep 10, 2019
I'll change the PR title as well after I commit the changes to the PR branch. I've got some college work to do for now, but I should be able to work on that later tonight or tomorrow. |
asvetlov
commented
Sep 10, 2019
|
That would make more sense, especially since this is done with
Hmm, okay. It just seemed odd to me to leave in the part in the last 4 lines of I'm not certain where the best place to call ...
loop=events.new_event_loop()
try:
events.set_event_loop(loop)
loop.set_debug(debug)
returnloop.run_until_complete(main)
finally:
try:
_cancel_all_tasks(loop)
loop.run_until_complete(loop.shutdown_asyncgens())
loop.shutdown_default_executor()
finally:
events.set_event_loop(None)
loop.close()Thanks for the feedback, and I greatly appreciate that you guys have allowed me to help with working on this issue. I've been learning a lot about the internals of asyncio during this process. (: |
asvetlov
commented
Sep 10, 2019
I think your last comment is correct. |
Updating the title to better reflect the changes and purpose of the PR. I'll update the PR itself after receiving approval from Yury on the implementation details. |
aeros
commented
Sep 10, 2019
I just realized that I forgot to set |
1st1
commented
Sep 10, 2019
They should remain as-is. The reasoning:
The Also, I'd make |
asvetlov
commented
Sep 10, 2019
@1st1 I understand the motivation but curious how it can be done in practice. Waiting is a synchronous call. |
1st1
commented
Sep 10, 2019
I'd just keep it simple and let the coroutine block. We can implement the "wait in a thread" solution later if we need to. Do you think this would be a bad idea? |
Oh crap, I just messed that up. I was attempting to update only the master branch in my fork, I did not mean to affect this PR branch. I'll try to revert this branch back to dbc08ae. Apologies for the spam messages, I'm still fairly new to using Git. I must have accidentally left it in the bpo-34037 branch when I made the changes instead of switching to master... |
Fixed, I successfully reverted the PR branch to dbc08ae. I would appreciate it if someone could remove the additional reviewers added to the PR, I don't have permission to do that. Sorry about the mess. |
asvetlov
commented
Sep 15, 2019
done |
aeros
commented
Sep 18, 2019
Normally, I haven't left the "Patch by " bit in the news entries for my own PRs, but since this one involved a significant amount of effort on my part, I'd like to do so. I'll update the news entry accordingly. |
asvetlov
commented
Sep 19, 2019
Let's merge it, there is no reason for waiting |
The only reason to wait was getting feedback from @1st1 and @vstinner on whether or not the "What's New" entry should be added, but that can be done at a later point if it's useful/necessary. All of the actual changes were finalized. Thanks for merging it! |
vstinner
commented
Sep 20, 2019
New features deserve an entry in the What's New (In Python 3.8) doc, yes. You can open a new PR for that. |
Based on a comment from @asvetlov#15735 (comment), this removes the provisional note for ``asyncio.run()`` in the documentation. Automerge-Triggered-By: @1st1
This PR was based heavily upon @vstinner's PR and the suggestions from @asvetlov to improve upon it:
@vstinner's PR was reverted due to it making too drastic of an API change for 3.8 and the concerns from @asvetlov about adding the property without providing public getter and setter methods.
However, the changes proposed still had significant support, and most importantly, it fixes a bug which has been causing intermittent failures within the CI tests for
test_asynciodue to dangling threads:Since this is involving changes to the public API, I fully plan on adding the appropriate changes to the documentation. But, I would prefer to wait until I receive feedback from @vstinner and @asvetlov about the implementation itself before doing so since they were both significantly involved in @vstinner's previous PR.
I'll cc the asyncio team as well in case anyone else has feedback to provide.
/cc @python/asyncio
https://bugs.python.org/issue34037