1

In a couple of answers (see here and here), when dealing with GUI + asyncio in separate threads, it suggests to use a queue when the asyncio loop needs to communicate with the GUI. However, when the GUI wants to communicate with the asyncio event loop it should use call_soon_threadsafe().

For example, one answer states:

When the event loop needs to notify the GUI to refresh something, it can use a queue as shown here. On the other hand, if the GUI needs to tell the event loop to do something, it can call call_soon_threadsafe or run_coroutine_threadsafe.

What I don't understand is why can the GUI not also use another Queue rather than call_soon_threadsafe()? i.e. can the GUI not put data on a queue for the asyncio loop to get and process? Is it just a design decision or is there some technical reason not to use a queue from GUI to asyncio loop?

martineau
  • 119,623
  • 25
  • 170
  • 301
SimpleOne
  • 1,066
  • 3
  • 12
  • 29
  • 1
    `call_soon_threadsafe` just means "execute this function in the event loop thread". It's totally up to you what the function will do, and putting something into an asyncio queue is a perfectly valid choice. It's not the _only_ choice, however - you might also want to set an event, start executing a coroutine, and so on. But whatever you do, you must do it from the event loop thread, otherwise (e.g. by using `call_soon` instead of `call_soon_threadsafe`) you risk the event loop to get corrupted or fail to notice the new event. – user4815162342 Sep 10 '20 at 12:28

1 Answers1

1

There's no appropriate queue class to use. asyncio.Queue isn't safe to interact with from outside the event loop, and queue.Queue would block the event loop.

If you want to use a queue anyway, you could use asyncio.run_coroutine_threadsafe to call an asyncio.Queue's put method.

user2357112
  • 260,549
  • 28
  • 431
  • 505
  • Ah, the ```queue.Queue``` blocking the event loop was the key bit for the penny to drop! Thanks. – SimpleOne Sep 10 '20 at 13:08
  • @SImpleOne. Queue.get() and Queue.put() block asyncio's event loop. Queue.get_nowait() and Queue.put_nowait() do not. These need to be polled by testing for Queue.empty() or Queue.full() respectively. If the operation has not completed then asyncio.sleep() and go back to try putting or getting again. – lemi57ssss Oct 13 '22 at 12:40