aio-libs / janus

Thread-safe asyncio-aware queue for Python

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

`RuntimeError: no running event loop` after upgrading to 0.5.0

martyanov opened this issue · comments

Unfortunately, changes in #246 broke the code that relies on creating an instance of janus.Queue outside of the scope of a running event loop, for no obvious reason.

Also, the behavior now contradicts with the behavior of asyncio.Queue.

>>> import asyncio
>>> asyncio.Queue()
<Queue at 0x7f76be085730 maxsize=0>
>>> import janus
>>> janus.Queue()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/user/projects/project/.venv/lib64/python3.8/site-packages/janus/__init__.py", line 29, in __init__
    self._loop = current_loop()
RuntimeError: no running event loop

Is there any good reason to not just use asyncio.get_event_loop? From performance perspective it shouldn't be significant.

In Python 3.8 and upwards, passing loop arguments to manay asyncio objects (including Queue) are marked to be deprecated.

In asyncio, the explicit passing of a loop argument has been deprecated and will be removed in version 3.10 for the following: asyncio.sleep(), asyncio.gather(), asyncio.shield(), asyncio.wait_for(), asyncio.wait(), asyncio.as_completed(), asyncio.Task, asyncio.Lock, asyncio.Event, asyncio.Condition, asyncio.Semaphore, asyncio.BoundedSemaphore, asyncio.Queue, asyncio.create_subprocess_exec(), and asyncio.create_subprocess_shell().

This means that instantiation of these objects outside the event loop (i.e., there is no running event loop in the current thread && the current line of code is not ultimately executed from a coroutine bound to a specific event loop) is now prohibited.
I think janus shoud follow the same behavior for consistency and to avoid deprecation warnings.

So, the new, intended way of use is to create janus/asyncio queues in a coroutine and lazily refer them in the synchronous counterparts.

Note that, asyncio.get_event_loop() implicitly creates a new event loop if there is no one, and this often causes having two event loops if the user code explicitly creates another one later.
This is usually not what people want and may cause undefined behaviors.

The new API, asyncio.get_running_loop() is now preferred across all asyncio-based codes, which generates an explicit error when there is no current event loop. All asyncio functions and classes are recommended to use it and the standard asyncio library is also migrating.

Are there any proofs that asyncio.get_event_loop will be replaced with asyncio.get_running_loop in asyncio.Queue, for example? I mean this will be refactored to use asyncio.get_running_loop. Deprecating and removing the loop argement is ok, but changing the internal behavior will break a lot of people's code.

All that is stated now is The loop argument is deprecated since Python 3.8, and scheduled for removal in Python 3.10. and many people think that their project is ready for upgrade, because they are not relying on explicit loop argument, but probably it will still break.

I understand the reasoning behind the changes, but the consequences are not that obvious at all.

The reason is: Queue does not exist without the loop.
The current version makes this dependency strict and explicit.
Sorry, this is not going to change