Description
- uvloop version: 0.15
- Python version: 3.8.6
- Platform: Ubuntu 18.04.3
- Can you reproduce the bug with
PYTHONASYNCIODEBUG
in env?: yes - Does uvloop behave differently from vanilla asyncio? How?: yes
I have been confused about this bug for about two weeks. In my situation, I create some threads and every thread run a new loop separately. At the same time, I have another thread to invoke loop.call_soon_threadsafe
to add tasks to loops in other threads. It ran well at first. However loops would close after a-few-hour running and raised RuntimeError('Event loop stopped before Future completed.')
. Actually some tasks still left in the loop and I haven't closed the loop yet.
Because this problem is really hard to reproduce . I took a long time to figure out how it happened and checked if I invoked loop.close
in somewhere. I added some log at close
and found the loop stopped suddenly without close
invocation. So I went on and checked libuv docs. There is a suspicious sentence If the loop is alive an iteration is started, otherwise the loop will exit immediately. So, when is a loop considered to be alive? If a loop has active and ref’d handles, active requests or closing handles it’s considered to be alive.
. I added some log in uv.uv_run
and it verified that the loop stoped because uv__loop_alive return False!
I dove into uvloop and libuv carefully. Disappointedly I found nothing. Code are rigorous and elegant. So I logged around every init and stop when uvloop invoke uv_handle_t
.Just like this
After a few hours execution and 200 thousand lines log file generated, I reproduced the bug again! And the highlight line is where the problem happened.
Because libuv isn't thread safe. The uv_loop_t.active_handles
will in race condition when we invoke call_soon_threadsafe
in a thread and the loop runs in another thread simultaneously. Actually the loop.handle_async.send
will activate the idle handle in the loop thread. So we don't need to activate the idle handle at call_soon_threadsafe
Here is my pull request. Approve please😊