🎓 A1Learner
🔍

Python Asyncio Patterns

Asyncio patterns are the queue, lock, and event tools that coroutines share.

Put and get with a queue

You await both put() and get() on an asyncio queue.

import asyncio

async def main():
    queue = asyncio.Queue()
    await queue.put("job")
    item = await queue.get()
    print(item)

asyncio.run(main())

Hold a lock with async with

async with holds the lock for the block. It releases the lock when the block ends.

import asyncio

async def main():
    lock = asyncio.Lock()
    async with lock:
        print("inside lock")

asyncio.run(main())

Wait for an event

wait() pauses until another coroutine sets the event. Here the event is already set.

import asyncio

async def main():
    event = asyncio.Event()
    event.set()
    await event.wait()
    print("ready")

asyncio.run(main())

Run a blocking call aside

run_in_executor() runs a normal function in a worker thread. The loop stays free while it runs.

import asyncio

def blocking():
    return "file read"

async def main():
    loop = asyncio.get_running_loop()
    result = await loop.run_in_executor(None, blocking)
    print(result)

asyncio.run(main())

Example

import asyncio

async def producer(queue):
    for word in ["pear", "apple", "kiwi"]:
        await queue.put(word)
    await queue.put(None)

async def consumer(queue, results):
    while True:
        item = await queue.get()
        if item is None:
            break
        results.append(item.upper())

async def main():
    queue = asyncio.Queue()
    results = []
    prod = asyncio.create_task(producer(queue))
    cons = asyncio.create_task(consumer(queue, results))
    await prod
    await cons
    for word in sorted(results):
        print(word)

asyncio.run(main())

Key points

  • Use asyncio.Queue to pass items between coroutines.
  • Use await queue.put() to add an item.
  • Use await queue.get() to take the next item.
  • Use asyncio.Lock to guard shared data between coroutines.
  • Use async with on a lock to hold it and release it.
  • asyncio.Event: a flag that coroutines can wait for and set.
  • Use run_in_executor() to run a blocking call outside the loop.
  • asyncio queues and locks belong to one event loop.
  • Queues, locks and events are the shared tools that coroutines work with.

In this example, the producer puts three words on the queue. It then puts None as a sentinel. A sentinel is a special value that means the work is done. The consumer takes items until it sees None. It stores each word in upper case. main() awaits both tasks and then prints the results sorted. Sorting makes the report order fixed.

Note

Use queue.Queue to share work between threads.

Try it Yourself

Edit the code, then press Run.

Running is simulated · Python Playground

Exercise

Why does the producer put None on the queue at the end?