-
Notifications
You must be signed in to change notification settings - Fork 51
New asyncWrap
helper to execute blocking calls on the native Qt event loop
#139
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
Conversation
My 2 cents: Can't you already wrap the syncronous function into an async one and call it from the asyncio event loop? |
This is a wrapping. What other wrapping are you suggesting? The trick here is to run the blocking method on the main thread, while the async caller Maybe I wasn't clear, but this is mostly to help with calling methods, like dialogue boxes, that re-enter the QT event loop. If called synchronously from an async slot, e.g. when popping up a modal, then your async loop can break, because you re-enter the task scheduling loop. This is a way to wrap the function to run on the same thread, effectively blocking the current task, but awaiting int in the async method, so that the called function can also call QT stuff. I think this is the only missing bit in converting a classic pyqt app into an async one. I was hit by so much trouble with modal dialogue boxes calling |
I'd like to ask a question about processEvents() invocation used in the provided "failing" example. Is there any reason why making that function async and adding an asyncio.sleep(0) invocation instead, which would return control back to the loop, allowing it to start the task, wouldn't fit your case? UPD. If there's something preventing one from doing that with real use cases, like with modals, it would be great to look at a more direct example. |
Sorry; just saw how the trick applies. Thanks! |
Looking at So, what is done here is lifting the continuation all the way up to the native Qt Event loop via QTimer, which prevents blocking of the python QEventLoop, as the continuation operates as another callback on native loop, which also allows you to continue native loop execution using some of the compatible Qt native methods directly, like This is useful, but I wonder if another name would be more expressive of what it actually does? Maybe something like |
Yeah, the I agree that The key here is that it allows async tasks to call the event loop again, re-enter it, such as when running and waiting for dialogue boxes. For me, it is sort of the opposite of The thing is, once you start using async slots in your app, soon the whole app migrates to one. Writing async logic, particularly more complex, longer running jobs, is the whole reason for doing so. But occasionally, those longer running slots will want to do something like displaying a confirmation message. This is where that comes in. Some suggestions:
Whatever you think best. Also, btw, I guess the Readme could do with a short description of the available methods/functions. (And not all of the api is exported from |
hm, I guess a simpler version, one that doesn't |
I think this would be great to list native methods that this could be useful with inside of the function docstring. As a dev who had worked with QML exclusively, I was unaware of native methods like I was aware about using |
I can see the benefit adding this to help handling modals, confirmation dialogues etc. As for the name (keeping the camel case because we're stuck with asyncSlot and asyncClose) something along the lines of:
The docstring can be a bit more descriptive about in which situation a user might want to reach for this function, maybe listing a couple of common cases/native functions that you have experienced before. |
Interesting. I am new to qt, but inherited an application in pyqt6 that I needed to convert to async. It had lots of those little confirmation modals run directly. I just assumed that this was how it was commonly done. |
Also another cosmetic question for @hosaka: |
@johnzhou721 I think time is better spent elsewhere than splitting |
Any objections to calling the function |
I think that the new docstring is great and properly explains the purpose of the method - at this point, the name does not matter that much. If this question refers to my previous comment, my concern regarding using "generic" names was that, some users, without consulting the documentation, might mistakenly infer from the name alone that this method automatically converts all synchronous or blocking functions into fully asynchronous-compatible ones, causing them to misuse it. But technically, such misuse is also possible if users put asyncSlot() everywhere thinking it would increase performance or magically unblock the UI... So better not to overthink it. |
Same, I'm not too bothered about the name. I wasn't referring to your comment specifically, just had to post something to get everyones attention :) @kristjanvalur if you're okay with my changes, we can merge this |
asyncWrap
helper to execute blocking calls on the native Qt event loop
Sure. Sorry, I've been on vacation and thus a bit late to respond. Great to see you appreciate this, thanks for the changes. Cheers! |
💯 |
This pr introduces a helper,
call_sync
, to call a synchronous method via the Qt event loop.This is useful to use from asynchronous methods, for example to invoke modal dialogue boxes via the
.exec()
method.If this is invoked directly from an async method, it can cause task re-entrancy in the asyncio scheduler.
By using
call_sync
, the re-entrant event loop call is done from the event loop itself with no actually running task in the scheduler.the name
call_sync
is just a suggestion, happy to change it.If this is not a good addition, then at least we could have a similar example to show how to achieve this.