uvloop
uvloop copied to clipboard
Loop.call_later(0) and Loop.call_later(-1) return a uvloop.loop.Handle and not an asyncio.TimerHandle
- uvloop version: master
- Python version: 3.10
- Platform: ubuntu
-
Can you reproduce the bug with
PYTHONASYNCIODEBUG
in env?: yes - Does uvloop behave differently from vanilla asyncio? How?: yes
Python 3.10.5 (main, Jun 11 2022, 16:53:24) [GCC 9.4.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import asyncio
>>> import uvloop
>>> uvloop.new_event_loop().call_later(-1, lambda: None)
<Handle <lambda>>
>>> asyncio.new_event_loop().call_later(-1, lambda: None)
<TimerHandle when=79332.145640902 <lambda>() at <stdin>:1>
>>>
the bug is here: https://github.com/MagicStack/uvloop/blob/5926386f81ea49903db9d5095058787ed91cff3d/uvloop/loop.pyx#L1327-L1328
@fantix I think the issue here is that uvloop should not use uv_idle_callback for call_soon,
Instead uvloop should schedule a timer for running with uv_timer_init set at -1
called "call_soon_handle"
for the loop.call_soon calls, whenever there are items added to the self._ready deque uvloop should start the "call_soon_handle", when the timer fires (note it will always fire first because it is the only timer scheduled at -1
) uvloop should then call all the recently added handles on the ready queue. If there are handles added to the ready queue at this point restart the call_soon_handle again.
for loop.call_later calls scheduled in the past uvloop should maintain an internal "self._call_later_expired". whenever call_soon_handle is called after calling all of the "_ready" callbacks uvloop should clear the original self._call_later_expired heap and then call all the handles in a copy of the call_later_expired heap
for call_later in the future the behavior can remain the same
import asyncio
import uvloop
from functools import partial
async def main():
loop = asyncio.get_running_loop()
loop.call_later(-0.5, partial(print, "4", end=""))
loop.call_later(-1, partial(print, "3", end=""))
loop.call_soon(partial(print, "1", end=""))
await asyncio.sleep(0)
print("2", end="")
print("asyncio")
asyncio.run(main())
print()
uvloop.install()
print("uvloop")
asyncio.run(main())
print()
# asyncio
# 1234
# uvloop
# 4312