Reputation: 566
I want to run coroutines in __init__
, I am using asyncio.create_task
to start the execution of the coroutine inside a non-async func (i.e. __init__
) to set instance attributes. I need to wait for the first task to finish before returning from __init__
. I cannot await
the task in __init__
, so I tried to use the result of task.done()
to check whether it's finished but it did not work, the code got hung and never returned from __init__
.
Here's a simple example:
async def coro():
await asyncio.sleep(2)
return 2
class Foo:
def __init__(self):
self._job_id_task = asyncio.create_task(coro()) #Starts running coro()
while not self._job_1_task.done():
pass
self.job_id = self._job_id_task.result()
foo = Foo() #gets hung and never returns Foo object.
Based on my sample code above, I was expecting foo = Foo()
to create Foo
object in little over 2 seconds, but execution on line foo = Foo()
gets hung and never finishes.
Upvotes: 2
Views: 3217
Reputation: 48
Your program is getting stuck because you are not running the event loop. You can run the event loop in another thread like this:
import asyncio
from threading import Thread
async def coro():
await asyncio.sleep(2)
return 2
def run_loop_in_thread(loop):
asyncio.set_event_loop(loop)
loop.run_forever()
loop = asyncio.get_event_loop()
coro_thread = Thread(target=run_loop_in_thread, args=(loop,))
coro_thread.start()
class Foo:
def __init__(self):
future = asyncio.run_coroutine_threadsafe(coro(), loop)
self.job_id = future.result()
foo = Foo()
Upvotes: 2
Reputation: 1
The simpler way would be to use run_until_complete
Your code would be like this:
import asyncio
async def coro():
await asyncio.sleep(2)
return 2
class Foo:
def __init__(self):
loop = asyncio.get_event_loop()
result =loop.run_until_complete(coro())
self.job_id = result
print(self.job_id)
foo = Foo() #gets hung and never returns Foo object.
Upvotes: 0