user6037143
user6037143

Reputation: 566

Python - Run coroutine from from sync function

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

Answers (2)

Robert Smith
Robert Smith

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

Rogério Vaz
Rogério Vaz

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

Related Questions