Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

asyncio, this event loop is already running issue

is it a good idea to run the asyncio eventloop inside a thread?

import asyncio
import time
from sample_threading import parallel
loop = asyncio.new_event_loop()

async def fn(p):
  for i in range(5):
    print(i)
    time.sleep(5)
  print("done")


@parallel
def th(p):
   loop.run_until_complete(fn(p))

th(1)
th(2)
th(3)

above code giving error

raise RuntimeError('This event loop is already running')
RuntimeError: This event loop is already running

any suggestion ?

like image 234
DmUser Avatar asked Oct 25 '25 05:10

DmUser


1 Answers

You can do that, but you have to explicitly start the event loop inside one - and only one - thread. I do not know the sample_threading.parallel decorator by heart, but I suppose it is automatically creating one thread for each call of your function?

In this case, when the second call is executed, the function runs in the second worker-thread, and tries to reuse the same loop you got a reference to in the global scope. It will work for the first worker thread, since the loop is not yet running, but will fail when you try it again.

Simply create one event loop for each thread you will have. I am not sure if having the threads created in an implicit and invisible way with this helper lib will make for a more maintainable project. (It already made the understanding of this initial problem harder, for example) - using the traditional threading.Thread() and thread.start() calls, with hard references to the running worker threads will likely be a better choice.

Other than that, just call asyncop.new_event_loop() in a function that runs inside your target worker threads, not on the global scope, and you should be good:


import asyncio
import time
import threading

async def fn(p):
  for i in range(5):
    print(i)
    time.sleep(5)
  print("done")

def thread_driver(p):
    loop = asyncio.new_event_loop()
    loop.run_until_complete(fn(p))



threads = [threading.Thread(target=thread_driver, args=(i,)) for i in range(1,4)]
[t.start() for t in threads()]


like image 200
jsbueno Avatar answered Oct 26 '25 18:10

jsbueno