Simple Guide to Python Asyncio

November 19, 2020

Note

Refer [Threading vs Multiprocessing vs Asyncio][python3-threading-vs-multiprocessing-vs-asyncio]

Asyncio is more lightweight than thread and suited for IO bound tasks, utilize single core only (concurrent but not parallel execution)

Multiple Process

import asyncio

async def run(name):
    for i in range(10):
        print(f"{name}", end='', flush=True)
        await asyncio.sleep(0.5)

    print(f"{name}[END]", end='', flush=True)

async def main():
    tasks = [run('a'), run('b'), run('c')]
    # wait for all task to finish
    await asyncio.gather(*tasks)

asyncio.run(main())
print('[STOP]')
abcabcabcabcabcabcabcabcabcabca[END]b[END]c[END][STOP]

Add Tasks Dynamically

  • Launch new tasks dynamically (one by one over time)
  • Quit when all tasks finished
import asyncio

async def run(name):
    for i in range(10):
        print(f"{name}", end='', flush=True)
        await asyncio.sleep(0.2)

    print(f"{name}[END]", end='', flush=True)

async def main():
    tasks = []
    task_names = ['a', 'b', 'c']

    while True:
        try:
            name = task_names.pop(0)
            if name:
                task = asyncio.create_task(run(name))
                tasks.append(task)
        except IndexError:
            pass

        done, pending = await asyncio.wait(tasks, timeout=1)

        if not pending:
            break


    print('main[END]', end='', flush=True)

asyncio.run(main())
print('[STOP]')

Shared Value

Since asyncio run on single Thread/CPU concurrently (not in parallel), it is safe to share value.

Increment a counter value. Using array or class object as mutable type; if you pass in integer (immutable type), it will just be a local value of each coroutines).

import asyncio

async def run(name, count):
    for i in range(10):
        await asyncio.sleep(0.5)
        count[0] += 1
        print(f"{name}[{count[0]}]", end='', flush=True)
    print(f"{name}[END]", end='', flush=True)

async def main():
    count = [0]
    tasks = [run('a', count), run('b', count), run('c', count)]
    # wait for all task to finish
    await asyncio.gather(*tasks)

asyncio.run(main())
print('[STOP]')
a[1]b[2]c[3]a[4]b[5]c[6]a[7]b[8]c[9]a[10]b[11]c[12]a[13]b[14]c[15]a[16]b[17]c[18]a[19]b[20]c[21]a[22]b[23]c[24]a[25]b[26]c[27]a[28]a[END]b[29]b[END]c[30]c[END][STOP]
This work is licensed under a
Creative Commons Attribution-NonCommercial 4.0 International License.