Home > OS >  asyncio end script when done
asyncio end script when done

Time:06-05

Can someone give me a tip on how to (understand asnycio) use asnycio to do this:

  1. on_start - method run only once when script starts
  2. get_sensor_readings - method run while event is True
  3. evauluate_data - method run while event is True
  4. check_time - method run while event is True to see if the event is still True
  5. on_end - method run only once when event has expired before script ends

This script below works, just simulating how long the method will execute I used random package await asyncio.sleep(random.randint(3, 9)) just to add some randomness for the bullet points above 2,3,4.

import asyncio
from datetime import datetime as dt
from datetime import timedelta as td
import random
import time

class Program:
    def __init__(self):
        self.duration_in_seconds = 60
        self.program_start = dt.now()
        self.event_has_expired = False


    async def on_start(self):
        print("On Start Event Start! Applying Overrides!!!")
        await asyncio.sleep(random.randint(3, 9))


    async def on_end(self):
        print("On End Releasing All Overrides!")
        await asyncio.sleep(random.randint(3, 9))
        

    async def get_sensor_readings(self):
        print("getting sensor readings!!!")
        await asyncio.sleep(random.randint(3, 9))   

 
    async def evauluate_data(self):
        print("checking data!!!")
        await asyncio.sleep(random.randint(3, 9))   


    async def check_time(self):
        if (dt.now() - self.program_start > td(seconds = self.duration_in_seconds)):
            self.event_has_expired = False
            print("Event is DONE!!!")

        else:
            print("Event is not done! ",dt.now() - self.program_start)



    async def main(self):

        # script starts, do only once self.on_start()
        await self.on_start()
        print("On Start Done!")
        
        while not self.event_has_expired:

            await self.get_sensor_readings()
            await self.evauluate_data()
            await self.check_time()

        # script ends, do only once self.on_end() when even is done
        await self.on_end()
        print('Done Deal!')


async def main():
    program = Program()
    await program.main()

asyncio.run(main())

What I notice is the scripts still keeps running

On Start Event Start! Applying Overrides!!!
going into event intermission mode
getting sensor readings!!!
checking data!!!
Event is not done!  0:00:23.131918
getting sensor readings!!!
checking data!!!
Event is not done!  0:00:31.211425
getting sensor readings!!!
checking data!!!
Event is not done!  0:00:43.272416
getting sensor readings!!!
checking data!!!
Event is not done!  0:00:52.362870
getting sensor readings!!!
checking data!!!
Event is DONE!!!
getting sensor readings!!!
checking data!!!
Event is DONE!!!
getting sensor readings!!!
checking data!!!
Event is DONE!!!
getting sensor readings!!!
checking data!!!

Any tips greatly appreciated. How do I cancel coroutines when the Event is DONE and then move into running the on_end method only once before the script ends?

CodePudding user response:

This appears to work:

import asyncio
from datetime import datetime as dt
from datetime import timedelta as td
import random
import time

class Program:
    def __init__(self):
        self.duration_in_seconds = 20
        self.program_start = dt.now()
        self.event_has_expired = False
        self.canceled_success = False

        

    async def on_start(self):
        print("On Start Event Start! Applying Overrides!!!")
        await asyncio.sleep(random.randint(3, 9))


    async def on_end(self):
        print("On End Releasing All Overrides!")
        await asyncio.sleep(random.randint(3, 9))
        

    async def get_sensor_readings(self):
        print("getting sensor readings!!!")
        await asyncio.sleep(random.randint(3, 9))   

 
    async def evauluate_data(self):
        print("checking data!!!")
        await asyncio.sleep(random.randint(3, 9))   


    async def check_time(self):
        if (dt.now() - self.program_start > td(seconds = self.duration_in_seconds)):
            self.event_has_expired = True
            print("Event is DONE!!!")

        else:
            print("Event is not done! ",dt.now() - self.program_start)



    async def main(self):
        # script starts, do only once self.on_start()
        await self.on_start()
        print("On Start Done!")

        while not self.canceled_success:

            readings = asyncio.ensure_future(self.get_sensor_readings())
            analysis = asyncio.ensure_future(self.evauluate_data())
            checker = asyncio.ensure_future(self.check_time())
            
            if not self.event_has_expired:
                await readings   
                await analysis           
                await checker
                
            else:
                # close other tasks before final shutdown
                readings.cancel()
                analysis.cancel()
                checker.cancel()
                self.canceled_success = True
                print("cancelled hit!")


        # script ends, do only once self.on_end() when even is done
        await self.on_end()
        print('Done Deal!')


async def main():
    program = Program()
    await program.main()

CodePudding user response:

Debugging nit: prior to await self.on_end() you should print something. Doesn't matter for this question, as apparently we never get that far.


You believe that check_time changed self.event_has_expired, yet the while loop doesn't see it change.

I am reading the documentation.

It suggests using a synchronization primitive such as a condition variable from the threading or perhaps from the asyncio libraries.

But now as I read the comments, I see that @svex99 correctly diagnosed the trouble -- you initialize the variable to False and then upon "change" you again make it False. So of course the while loop will never terminate.

Let us know how testing goes once you adjust that detail.

  • Related