简体   繁体   中英

python asyncio run infinite loop in background and access class variable from the loop

I have a class Sensor which has one numeric value num . It has an async method update , which updates the num every second in an infinite loop.

I want to initiate the class and call the method update , keep it running and return the control to the main program to access the value of the num after some time. I am using asyncio but do not know how to invoke the method such that the concurrent running of the loop and variable access is feasible.

Code:

import asyncio
import time


class Sensor:
    def __init__(self, start=0):
        self.num = start

    async def update(self):
        print(f"Starting Updates{self.num}")
        while True:
            self.num += 1
            print(self.num)
            await asyncio.sleep(1)


if __name__ == "__main__":
    print("Main")
    sensor = Sensor()
    # asyncio.run(sensor.update())
    # asyncio.ensure_future(sensor.update())
    future = asyncio.run_coroutine_threadsafe(sensor.update(), asyncio.new_event_loop())
    print("We are back")
    print(f"current value: {sensor.num}")
    time.sleep(4)
    print(f"current value: {sensor.num}")


This gives me output of 0 before and after waiting for 4 seconds, which means the update method is not running behind. run() does not return the control at all.

Which method should I call to invoke the infinite loop in the background?

To use asyncio.run_coroutine_threadsafe , you need to actually run the event loop, in a separate thread. For example:

sensor = Sensor()
loop = asyncio.new_event_loop()
threading.Thread(target=loop.run_forever).start()
future = asyncio.run_coroutine_threadsafe(sensor.update(), loop)
...
loop.call_soon_threadsafe(loop.stop)

According to documents for running tasks concurrently, you should use gather . For example, your code will be something like this:

import asyncio
import time


class Sensor:
    def __init__(self, start=0):
        self.num = start

    async def update(self):
        print(f"Starting Updates{self.num}")
        while True:
            self.num += 1
            print(self.num)
            await asyncio.sleep(1)


async def print_value(sensor):
    print("We are back")
    print(f"current value: {sensor.num}")
    await asyncio.sleep(4)
    print(f"current value: {sensor.num}")


async def main():
    print("Main")
    sensor = Sensor()
    await asyncio.gather(sensor.update(), print_value(sensor))

if __name__ == "__main__":
    asyncio.run(main())

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM