asyncio - how to stop background task cleanly

Marko Rauhamaa marko at pacujo.net
Sat Feb 6 10:34:47 EST 2016


"Frank Millman" <frank at chagford.com>:

> "Marko Rauhamaa"  wrote in message news:87lh6ys052.fsf at elektro.pacujo.net...
>> You should
>>
>>    await asyncio.wait(..., return_when=asyncio.FIRST_COMPLETED)
>>
>> to deal with multiple alternative stimuli.
>>
>
> Thanks, Marko, that works very well.
>
> [...]
>
> Now I just have one problem left. I will keep experimenting, but if
> someone gives me a hint in the meantime it will be appreciated.
>
> I run my background task like this -
>
>    stop_task = False
>
>    async def background_task():
>        while not stop_task:
>            await perform_task()
>            await asyncio.sleep(10)

You should set up a separate asyncio.Event or asyncio.Queue to send
"out-of-band" signals to your background_task:

    async def background_task(cancel_event):
         async def doze_off():
             await asyncio.sleep(10)

         while True:
             await asyncio.wait(
                 perform_task, cancel_event.wait,
                 return_when=asyncio.FIRST_COMPETED)
             if cancel_event_is_set()
                 break
             await asyncio.wait(
                 doze_off, cancel_event.wait,
                 return_when=asyncio.FIRST_COMPETED)
             if cancel_event_is_set()
                 break

That should be the idea, anyway. I didn't try it out.

> I stop the task by setting stop_task to True. It works, but it waits for
> the 10-second sleep to expire before it is actioned.
>
> With threading, I could set up a threading.Event(), call
> evt.wait(timeout=10) to run the loop, and evt.set() to stop it. It
> stopped instantly.
>
> Is there an equivalent in asyncio?

Yes, you could simplify the above thusly:

    async def background_task(cancel_event):
         while True:
             await asyncio.wait(
                 perform_task, cancel_event.wait,
                 return_when=asyncio.FIRST_COMPETED)
             if cancel_event_is_set()
                 break
             await asyncio.wait(
                 cancel_event.wait, timeout=10,
                 return_when=asyncio.FIRST_COMPETED)
             if cancel_event_is_set()
                 break


Marko


More information about the Python-list mailing list