New submission from Hrvoje Nikšić <hnik...@gmail.com>:

Looking at StackOverflow's python-asyncio tag[1], it appears that it's a very 
common mistake for users to invoke asyncio functions or methods from a thread 
other than the event loop thread. In some cases this happens because the user 
is careless with threads and hasn't read the documentation. But in many cases 
what happens is that a third-party library invoked a callback in a different 
thread without making it transparent that that's what it's doing.

The trouble is that in many cases doing these things, e.g. calling 
loop.call_soon() or loop.create_task() from the wrong thread, will *appear to 
work*. The typical event loop is busy servicing different coroutines, so a 
function or task enqueued without a proper wakeup gets picked up soon enough. 
This is, of course, a disaster waiting to happen because it could easily lead 
to corruption of event loop's data structures. But users don't know that, and 
many of them become aware of the problem only after wondering "why does my code 
start working when I add a coroutine that does nothing but asyncio.sleep(0.1) 
in an infinite loop?" Some may never even fix their code, just assuming that 
asyncio takes a long time to process a new task or something like that.

I suggest that asyncio should be stricter about this error and that methods and 
functions that operate on the event loop, such as call_soon, call_later, 
create_task, ensure_future, and close, should all call _check_thread() even 
when not in debug mode. _check_thread() warns that it "should only be called 
when self._debug == True", hinting at "performance reasons", but that doesn't 
seem justified. threading.get_ident() is efficiently implemented in C, and 
comparing that integer to another cached integer is about as efficient an 
operation as it gets.

The added benefit would be a vast improvement of robustness of asyncio-based 
programs, saving many hours of debugging.


[1]
Here is an incomplete list of questions where the users stumbled on this 
problem, and that's only from the last three months or so:

https://stackoverflow.com/questions/49906034/python-asyncio-run-forever-and-tasks
https://stackoverflow.com/questions/49851514/python-websockets-and-gtk-confused-about-asyncio-queue
https://stackoverflow.com/questions/49533612/using-asyncio-loop-reference-in-another-file
https://stackoverflow.com/questions/49093623/strange-behaviour-when-task-added-to-empty-loop-in-different-thread
https://stackoverflow.com/questions/48836285/python-asyncio-event-wait-not-responding-to-event-set
https://stackoverflow.com/questions/48833644/how-to-wait-for-asynchronous-callback-in-the-background-i-e-not-invoked-by-us
https://stackoverflow.com/questions/48695670/running-asynchronous-code-synchronously-in-separate-thread

----------
components: asyncio
messages: 317324
nosy: asvetlov, hniksic, yselivanov
priority: normal
severity: normal
status: open
title: Detect accessing event loop from a different thread outside of _debug
type: enhancement
versions: Python 3.7, Python 3.8

_______________________________________
Python tracker <rep...@bugs.python.org>
<https://bugs.python.org/issue33605>
_______________________________________
_______________________________________________
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com

Reply via email to