Skip to content
AITroveRead. Build. Understand.
Make this comfortable

Python asyncio loop callbacks: submit from a worker with call_soon_threadsafe

Last updated: 1 Oct 20265 min read
tutorial
IntermediateBy AITrove Editorial

A worker thread must hand a callback to the event loop through a thread-safe scheduling method.

Download Python source kit

Operation contract

The loop owns an asyncio.Event and a receipt list. A worker thread schedules a callback that appends receipt 47 and sets the event. The coroutine waits for that event, joins the worker after delivery, and reads the loop-owned list.

Failure boundary

The callback is short and runs on the loop thread; it must not perform blocking I/O. The worker keeps a reference to a live loop only for this bounded fixture. In a service, shutdown must stop submissions before closing the loop, and an Event wait needs a deadline.

Working program

python
import asyncio
from threading import Thread

async def collect_receipt():
    loop = asyncio.get_running_loop()
    delivered = asyncio.Event()
    receipts = []

    def accept_on_loop():
        receipts.append(47)
        delivered.set()

    worker = Thread(target=lambda: loop.call_soon_threadsafe(accept_on_loop))
    worker.start()
    await asyncio.wait_for(delivered.wait(), timeout=2)
    worker.join()
    print("receipts", receipts)

asyncio.run(collect_receipt())

Output

Output
receipts [47]

Costs and limits

Scheduling one callback is small, but unbounded worker submissions can still overfill a loop's ready queue. A real producer needs admission control and a shutdown handshake.

Common Mistakes

  • Do not call a loop's ordinary call_soon from a different thread.
  • Do not run blocking work inside the scheduled callback.
  • A closed loop cannot accept new callbacks; stop producers first.

Connected lessons

Test this contract.

python
loop-call-soon-threadsafe
Storage details