pythonpython-asyncio

How can I pause & resume a task in asyncio?


Let's say I have a background task that's looping through existing orders (doing some manipulations if necessary). Now if I want to add an order, this background task should stop while I'm placing a new order and resume when I am finished.

In pseudo-code:

async def loop_orders():
    while True:
        do_this()
        do_that()
    return

async def create_order():
    stop_loop_orders()
        ...
        send_order()
    resume_loop_orders()
    return

I couldn't figure out which of these two is the way to go:


Solution

  • You cannot suspend and resume an asyncio task.

    You could cancel the task and later create a new one, but this leads to more problems than it solves. Data consistency may be compromised and the new task will not resume exactly where the previous one was interupted.

    You could easily make the task wait at some specific point (or points)

    async def loop_orders():
        while True:
            ... wait here while paused ...
            do_this()
            do_that()
    

    but when the create_order pauses the loop_orders task, the former must wait until the latter reaches that point where it pauses - the create_order task requests a pause and the loop_orders acknowledges.

    I made a little demo with two Events that I named enable and idle in an attempt to make the method names .clear, .set and .wait match the logic.

    import asyncio
    
    enable = None
    idle = None
    
    async def loop_orders():
        while True:
            idle.set()
            await enable.wait()
            idle.clear();
            print("processing order ... ", end="", flush=True)
            await asyncio.sleep(0.7)
            print("done")
    
    async def create_order():
        enable.clear();
        await idle.wait()
        print("-- pause start ... ", end="", flush=True)
        await asyncio.sleep(2)
        print("stop")
        enable.set()
    
    async def test():
        global enable, idle
    
        enable = asyncio.Event()
        enable.set()    # initial state = enabled
        idle = asyncio.Event()
    
        asyncio.create_task(loop_orders())
        await asyncio.sleep(2)
        await create_order()
        await asyncio.sleep(2)
        await create_order()
        await asyncio.sleep(1)
        print("EXIT")
    
    
    asyncio.run(test())