2

I am studying Asyncio and so far I managed to prepare the structure for what I need.

import asyncio
import random

async def speed_forever():
    while True:
        speed = random.randint(1,100)
        print("Speed mesuring ......", speed)
        await asyncio.sleep(1)

async def rain_forever():
    while True:
        rain = random.random()
        print("Rain mesuring .......", rain)
        await asyncio.sleep(0.1)


async def main():
    asyncio.ensure_future(speed_forever())  # fire and forget
    asyncio.ensure_future(rain_forever())  # fire and forget

    while True:
        print("*" * 40)
        print("Sending Data.....")    #Here I'd like to get access to rain and speed variable by using a queue
        print("*" * 40)
        await asyncio.sleep(5)
     

if __name__ == '__main__':
    loop = asyncio.get_event_loop()
    loop.run_until_complete(main())


Now, I'd like to get access to rain and speed from main() so can do something with those variables (eg sending over the air).

  1. How should I implement a queue because I am failing at it?
  2. Is the code structure good enough to start implementing the function with the real code?
3
  • speed_forever and rain_forever should be methods of a class. speed and rain should be attributes of the same class. Commented Jun 22, 2020 at 11:29
  • Would you like to get all the measurements in main (e.g., from the last 5 seconds) or just the very last one? Commented Jun 22, 2020 at 11:35
  • The very last available. Commented Jun 22, 2020 at 11:39

1 Answer 1

1

Here's a skeleton for passing data from the *_forever functions back to main over a couple of queues. I've marked the new code with '***'

import asyncio
import random

rain_q = asyncio.Queue()      # ***
speed_q = asyncio.Queue()     # ***

async def speed_forever():
    while True:
        speed = random.randint(1,100)
        print("Speed mesuring ......", speed)
        await speed_q.put(speed)                 # ***
        await asyncio.sleep(1)

async def rain_forever():
    while True:
        rain = random.random()
        print("Rain mesuring .......", rain)
        await rain_q.put(rain)                   # ***
        await asyncio.sleep(0.1)


async def main():
    asyncio.ensure_future(speed_forever())  # fire and forget
    asyncio.ensure_future(rain_forever())  # fire and forget

    rain = None       # *** 
    speed = None      # ***
    while True:
        print("*" * 40)

        # *** Read stuff from the queues. Here, I'm just using the latest
        # item in the queue - but one can do other things as well. 
        while not rain_q.empty(): 
            rain = await rain_q.get()
        
        while not speed_q.empty(): 
            speed = await speed_q.get()

        print(f"*** Last rain was {rain}")            
        print(f"*** Last speed was {speed}")
        print("Sending Data.....")    #Here I'd like to get access to rain and speed variable by using a queue
        print("*" * 40)
        await asyncio.sleep(5)

     

if __name__ == '__main__':
    loop = asyncio.get_event_loop()
    loop.run_until_complete(main())

Note that if all you're interested in is the last item in the queue, there are other ways to achieve this. One, for example, would be a global variable of type float with the latest number. I don't think that's the right way to do it in this case.

Sign up to request clarification or add additional context in comments.

8 Comments

I see now speed has got all the values set in the queue. Speed was 88 Speed was 44 Speed was 89 Speed was 23 Speed was 82 Is there a way to just fetch most recent speed value from the queue and then clear it?
so if I understand correctly, you're basically looking for a queue of size 1, which always keeps just the last item?
yes exactly, I acquire a new value every 3 seconds but probably send out last value (which is averaged) every minute over the air
The while loops in main() are not correct. When the queue becomes empty, the inner loop won't be entered, and the outer loop will loop forever. Since the outer loop doesn't await anything, no other coroutines will run and get a chance to put something in the queue. The correct (and simpler) approach is to drop the inner loop and simply unconditionally use rain = await rain_q.get() in the outer while True. If the queue is not empty, that will give the next item. If it's empty, get() will pause the current coroutine until an item becomes available - which is exactly what you want.
@Dan You're right. The rest of the comment should still apply, though.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.