question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Differences between quamash and asyncio event loop + processEvents

See original GitHub issue

Hello,

I was wondering what would be the implication of using the asyncio event loops for a Qt application instead of quamash Event loop.

We can use asyncio with Qt with the following simple code. The app must be killed to be stopped but you get the point :

    async def process_events(qapp):
        while True:
            await asyncio.sleep(0)
            qapp.processEvents()

    qapp = QApplication(sys.argv)
    loop = asyncio.get_event_loop()
    loop.run_until_complete(process_events(qapp))

So what does Quamash brings in terms of compatibility and stability with the Qt system compared to asyncio event loop ? Or is it only about a proof of concept ?

The first thing I can see is that asyncio + modal dialogs does not working easiliy. But I wonder if there are more things to know that I’m not aware of ?

Thanks

Issue Analytics

  • State:open
  • Created 7 years ago
  • Comments:21 (16 by maintainers)

github_iconTop GitHub Comments

2reactions
enkorecommented, Aug 20, 2018

A major difference I didn’t see mentioned here is quamash only working for the main application event loop, i.e. QApplication’s main/UI thread. Meanwhile the “let’s put an event loop in an event loop so you can loop while you loop”-approach actually works for arbitrary QThreads. Sample code:

class ...(QObject):
    @pyqtSlot()
    def run(self):
        # Connected to QThread.started; thus will be called in the new thread.
        asyncio.set_event_loop(asyncio.new_event_loop())
        self.evloop = asyncio.get_event_loop()
        self.evloop.run_until_complete(self.run_event_loop())

    async def run_event_loop(self):
        """
        Runs the event loop. Will only complete if the thread receives an interruption request
        (QThread.requestInterruption()).

        Since we are using asyncio only for coordination, the loop will block for Qt events.
        """
        thread = self.thread()
        while not thread.isInterruptionRequested():
            await asyncio.sleep(0)
            thread.eventDispatcher().processEvents(QEventLoop.AllEvents|QEventLoop.WaitForMoreEvents)

The sequence to get such a thread to join is thus as follows:

thread.requestInteruption()  # Set interruption request flag
thread.eventDispatcher().wakeup()  # Causes processEvents() to return even if no real events arrive
thread.quit()  # Causes event loop to quit (the one running in QThread.run, not run_event_loop())
thread.join()  # Thread will exit now and can be joined.

I am using this in the context of QNetworkAccessManager, where I have the ability to retry requests and such things, but I also wanted to avoid the signal/callback-oriented approach, since that tends to get messy fast.

Thus, the actual events driving this and completing futures is the QNetworkReply status slots explicitly setting the results on futures previously created. The event loop of asyncio is only around to resume coroutines as the futures they’re waiting on enter done status.

2reactions
Insoleetcommented, Sep 10, 2016

Ok so I did a fast implementation of the option ( https://github.com/Insoleet/quamash/tree/perfs ) :

  • use a single simple timer and key off the timerId more

This implementation breaks Executor tests, and notably the ones about subprocesses , but it was enough to run the benchmark.

It looks a bit better but that still not as good as standard asyncio :

Results for run_aiohttp
RPS: 1017,  mean: 477.999 ms,   standard deviation 70.280 ms    median 468.330 ms
Results for run_aiohttp_quamash
RPS: 699,   mean: 694.200 ms,   standard deviation 105.264 ms   median 689.685 ms

callgraph-quamash

Any idea maybe ?

Read more comments on GitHub >

github_iconTop Results From Across the Web

5.6.1.1. asynchronous programming in python 3
The idea behind async programming in python 3 is to avoid callbacks ... QEventLoop() asyncio.set_event_loop(loop) # set the qt event loop as the...
Read more >
harvimt/quamash - Gitter
you could in theory use asyncio/event loops ... if you don't call app.exec_() it can't process events, and your app freezes. Gustavo Goretkin....
Read more >
Event Loop — Python 3.11.1 documentation
The event loop is the core of every asyncio application. Event loops run asynchronous tasks and callbacks, perform network IO operations, and run...
Read more >
Run Qt and Websockets server in same event loop
app.exec() runs QT's event loop, which you can't do since you have to run asyncio's event loop with run_forever() .
Read more >
Integrating insync into a responsive GUI application - Groups.io
processEvents () in an attempt to force the GUI to update itself ... RuntimeError: There is no current event loop in thread 'Dummy-6'....
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found