Asyncio in Corroutine Runtimeerror: No Running Event Loop

python3.8 RuntimeError: no running event loop

You have to pass the loop as argument to the .all_tasks() function:

pending = asyncio.all_tasks(loop)

Output:

<_UnixSelectorEventLoop running=False closed=False debug=False>
<_GatheringFuture pending>
Results: [8, 5, 2, 9, 6, 3, ZeroDivisionError('division by zero'), 7, 4, 1]

So for a full correction of your script:

import asyncio

async def f(delay):
if delay:
await asyncio.sleep(1 / delay)
return delay

loop = asyncio.get_event_loop()
for i in range(10):
loop.create_task(f(i))

print(loop)
pending = asyncio.all_tasks(loop)
group = asyncio.gather(*pending, return_exceptions=True)
results = loop.run_until_complete(group)
print(f'Results: {results}')
loop.close()

asyncio.run() cannot be called from a running event loop when using Jupyter Notebook

The asyncio.run() documentation says:

This function cannot be called when another asyncio event loop is running in the same thread.

In your case, jupyter (IPython ≥ 7.0) is already running an event loop:

You can now use async/await at the top level in the IPython terminal and in the notebook, it should — in most of the cases — “just work”. Update IPython to version 7+, IPykernel to version 5+, and you’re off to the races.

Therefore you don't need to start the event loop yourself and can instead call await main(url) directly, even if your code lies outside any asynchronous function.

Jupyter / IPython

async def main():
print(1)

await main()

Python (≥ 3.7) or older versions of IPython

import asyncio

async def main():
print(1)

asyncio.run(main())

In your code that would give:

url = ['url1', 'url2']
result = await main(url)

for text in result:
pass # text contains your html (text) response

Caution

There is a slight difference on how Jupyter uses the loop compared to IPython.

When running my Discord bot I get a RuntimeError: no running event loop {FIXED}

Your initialization of a loop is wrong, it should be:

client.loop.create_task(lightswitch_task())
client.loop.create_task(version_update_background_task())
client.run()

Python create_task does not work in running event loop

When creating task from outside the event loop thread, you need to use asyncio.run_coroutine_threadsafe. That function will schedule the coroutine in a thread-safe manner and notify the event loop that there is new work to be done. It will also return a concurrent.futures.Future object which you can use to block the current thread until the result is available.

From surface it looks like tasks created in running event loop do not get executed. But why is that?

Calling create_task is insufficient because it doesn't contain code to "wake up" the event loop. This is a feature - such wakeup is normally not needed, and adding it would just slow down the regular single-threaded use. When create_task is invoked from the event loop thread, it is inside an event loop callback, so the event loop can check its task queue as soon as it regains control, when it is done executing the callback. But when create_task is invoked from a different thread, the event loop is asleep waiting for IO, so run_coroutine_threadsafe is needed to wake it up.

To test this, you can create a "heartbeat" coroutine, which only contains an infinite loop that prints something and awaits asyncio.sleep(1). You'll see that the tasks created with create_task get executed along with the heartbeat, which also happens to wake up the event loop. In busy asyncio applications this effect can give the impression that create_task from another thread "works". However, this should never be relied on, as create_task fails to implement proper locking and could corrupt the event loop internals.

I have not seen anything regarding this in documentation.

Take a look at the concurrency and multithreading section.

Discord Bot Asynchronous Loop Failure

To start a task you need a running event loop.

If you want to use run(), you can start the task in setup_hook where all your async setup should be unless it is cog specific in which case you can put them in cog_load:

from typing import Any

class MyClient(discord.Client):

def __init__(self, *, intents: discord.Intents, **options: Any) -> None:
super().__init__(intents=intents, **options)

async def setup_hook(self) -> None:
channelname.start()

client = MyClient(intents=discord.Intents.default())

client.run('bot token')

or:

import asyncio

async def main():
async with client:
channelname.start()
await client.start('bot token')

asyncio.run(main())

Also, in your task you are operating on two offset-aware and naive datetime objects which is not allowed, you are probably getting an error but since you don't have an error handler setup it's getting eaten by it.

Do this instead:

msg_secs = (datetime.datetime.now().timestamp() - message.created_at.timestamp())

Instead of flatten(), use this, if you are on 2.0:

messages = [message async for message in channel.history(limit=2)]


Related Topics



Leave a reply



Submit