Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to start coroutines and continue with synchronous tasks?

I am trying to understand asyncio and port my undestanding of threading. I will take the example of two threads running indefinitely and a non-threaded loop (all of them outputting to the console).

The threading version is

import threading
import time

def a():
    while True:
        time.sleep(1)
        print('a')

def b():
    while True:
        time.sleep(2)
        print('b')

threading.Thread(target=a).start()
threading.Thread(target=b).start()
while True:
        time.sleep(3)
        print('c')

I now tried to port this to asyncio based on the documentation.

Problem 1: I do not understand how to add the non-threaded task as all examples I saw show an ongoing loop at the end of the program which governs the asyncio threads.

I then wanted to have at least the two first threads (a and b) running in parallel (and, worst case, add the third c as a thread as well, abandonning the idea of mixed thread and non-threded operations):

import asyncio
import time

async def a():
    while True:
        await asyncio.sleep(1)
        print('a')

async def b():
    while True:
        await asyncio.sleep(2)
        print('b')

async def mainloop():
    await a()
    await b()

loop = asyncio.get_event_loop()
loop.run_until_complete(mainloop())
loop.close()

Problem 2: The output is a sequence of a, suggering that the b() coroutine is not called at all. Isn't await supposed to start a() and come back to the execution (and then start b())?

like image 650
WoJ Avatar asked Aug 20 '17 09:08

WoJ


1 Answers

await stops execution at a point, you do await a(), and you have an infinite loop in a(), so it's logical b() doesn't get called. Think about it as if you insert a() in mainloop().

Consider this example:

async def main():
    while True:
        await asyncio.sleep(1)
        print('in')

    print('out (never gets printed)')

To achieve what you want you need to create a future which would manage multiple coroutines. asyncio.gather is for that.

import asyncio


async def a():
    while True:
        await asyncio.sleep(1)
        print('a')


async def b():
    while True:
        await asyncio.sleep(2)
        print('b')


async def main():
    await asyncio.gather(a(), b())


loop = asyncio.get_event_loop()
loop.run_until_complete(main())
loop.close()
like image 52
Danil Speransky Avatar answered Nov 05 '22 10:11

Danil Speransky