简体   繁体   English

如何在 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:我无法弄清楚这两个中的哪一个是要走的路:

  • asyncio.Lock : What is locked? asyncio.Lock :什么是锁定的? How do I define what should be locked?我如何定义应该锁定的内容?
  • asyncio.Event : The wait() method would " Wait until the event is set. " => but I would rather need a " wait if the event is set " functionality. asyncio.Event :wait() 方法将“等到事件被设置。 ”=> 但我宁愿需要“如果事件被设置,等待”功能。

My first idea was我的第一个想法是

lock = asyncio.Lock()

async def loop_orders():
    while True:
        if not lock.locked():
            do_this()
            do_that()

async def create_order():
    async with lock:
        send_order()

So before sending order it sets lock so if not lock.locked(): should skip do_this() do_that() .所以在发送订单之前它会设置lock所以if not lock.locked():应该跳过do_this() do_that() But code can run somewhere inside do_this() do_that() and then lock.locked() can't stop it.但是代码可以在do_this() do_that()内的某个地方运行,然后lock.locked()无法阻止它。 So maybe it should be in both所以也许它应该在两者中

lock = asyncio.Lock()

async def loop_orders():
    while True:
        async with lock:
            do_this()
            do_that()

async def create_order():
    async with lock:
        send_order()

This way when it starts sending then it has to wait with do_this() do_that() .这样,当它开始发送时,它必须等待do_this() do_that() And when it starts do_this() do_that() then it has to wait with send_order()当它开始do_this() do_that()然后它必须等待send_order()


BTW:顺便提一句:

If you want to understand it then in normal code it could look like如果你想理解它,那么在普通代码中它可能看起来像

lock = False

async def loop_orders():
    global lock

    while True:

        # wait if `lock` was set `True` in other function(s)
        while lock:         
            pass

        # set `True` to block other function(s)
        lock = True

        do_this()
        do_that()

        # set `False` to unblock other function(s)
        lock = False

async def create_order():
    global lock

    # wait if `lock` was set `True` in other function(s)
    while lock:
        pass

    # set `True` to block other function(s)
    lock = True

    send_order()

    # set `False` to unblock other function(s)
    lock = False

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.但是当create_order暂停loop_orders任务时,前者必须等到后者到达它暂停的点 - create_order任务请求暂停并且loop_orders确认。

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.我用我命名为enableidle两个Events做了一个小演示,试图使方法名称.clear.set.wait与逻辑匹配。

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())

First of all, I think you should maybe consider implementing this as a producer/consumer pattern using a Queue.首先,我认为您应该考虑使用队列将其实现为生产者/消费者模式。

But if you really want to suspend the execution of a Task , you can take a look at this question .但是如果你真的想暂停一个Task的执行,你可以看看这个问题

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM