Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unable to understand behavior of Future.set_result on futures in another thread

I want a class function to pause execution till value of a class variable is changed as requested by the function by another thread. I am new to python asyncio module.

asyncio.Future seem to provide a mechanism for waiting for future value hence I tried following on a toy example:

class RandomReader:
    def __init__(self):
        self.loop = asyncio.get_event_loop()
        self.service = 3
        self.thread = threading.Thread(target=self.reader)
        self.thread.start()
        self.futures: Dict[int, asyncio.Future] = {}

    def reader(self):
        asyncio.set_event_loop(self.loop)
        while self.service != 0:
            k, v = read()
            if k in self.futures:
                if self.futures[k].done():
                    continue

                self.futures[k].set_result(v)
                self.service -= 1

    async def wait(self, v: int):
        self.futures[v] = self.loop.create_future()
        a = await self.futures[v]
        logging.debug("value %d received %f", v, a)
        return v, a

The read function above reads random key and values that potentially match with wait.

Calling function makes calls like below 3 times (RandomReader.service)

    t1 = asyncio.create_task(random_reader.wait(3))
    print(await t1)

I expected self.futures[k].set_result(v) to assign value to a in wait function like documentation of Future object, but the await doesn't actually execute. Though status of futures in self.futures does change to "FINISHED".

Any help with this is really appreciated.

like image 204
Pushkar Nimkar Avatar asked Oct 30 '25 04:10

Pushkar Nimkar


1 Answers

Asyncio futures are not thread-safe - nor is any other asyncio API, except where explicitly noted otherwise. To mark a future as done from a different thread, use call_soon_threadsafe:

self.loop.call_soon_threadsafe(self.futures[k].set_result, v)

That call will notify the event loop that something is going on, and will have the event loop set the future's result, immediately noticing it and waking up the awaiting coroutine.

Also note that the call to asyncio.set_event_loop() in reader() does not look correct, since the event loop is in fact not running in reader's thread.

like image 158
user4815162342 Avatar answered Nov 01 '25 19:11

user4815162342



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!