如何在 asyncio 中暂停和恢复任务?
How can I pause & resume a task in asyncio?
假设我有一个循环遍历现有订单的后台任务(必要时进行一些操作)。
现在,如果我想添加订单,这个后台任务应该在我下新订单时停止,并在我完成后恢复。
在伪代码中:
async def loop_orders():
while True:
do_this()
do_that()
return
async def create_order():
stop_loop_orders()
...
send_order()
resume_loop_orders()
return
我无法弄清楚这两个中的哪一个是要走的路:
- asyncio.Lock: 锁定了什么?我如何定义应该锁定的内容?
- asyncio.Event:wait() 方法将“等待事件设置。”=> 但我宁愿需要一个“等待 if 事件设置”功能。
我的第一个想法是
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()
所以在发送订单之前它设置 lock
所以 if not lock.locked():
应该跳过 do_this() do_that()
。但是代码可以 运行 在 do_this() do_that()
的某处然后 lock.locked()
无法阻止它。所以也许它应该在两者中
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()
这样当它开始发送时它必须等待do_this() do_that()
。当它开始时 do_this() do_that()
然后它必须等待 send_order()
顺便说一句:
如果你想理解它,那么在普通代码中它可能看起来像
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
顺便说一句:
我认为您可以以类似的方式使用 Event
,但您应该以不同的方式思考:您可以使用 wait if the event is **unset**/**clear**
而不是 wait if the event is set
您不能暂停和恢复异步任务。
您可以取消任务并稍后创建一个新任务,但这导致的问题多于解决的问题。数据一致性可能会受到影响,新任务将不会在前一个任务中断的地方恢复。
您可以轻松地让任务在某个特定点(或多个点)等待
async def loop_orders():
while True:
... wait here while paused ...
do_this()
do_that()
但是当 create_order
暂停 loop_orders
任务时,前者必须等到后者到达它暂停的那个点 - create_order
任务请求暂停并且 loop_orders
确认。
我用两个 Events
做了一个小演示,我将它们命名为 enable
和 idle
,试图使方法名称为 .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())
首先,我认为您或许应该考虑使用队列将其实现为 producer/consumer 模式。
但是如果你真的想暂停执行一个Task
,你可以看看这个。
假设我有一个循环遍历现有订单的后台任务(必要时进行一些操作)。 现在,如果我想添加订单,这个后台任务应该在我下新订单时停止,并在我完成后恢复。
在伪代码中:
async def loop_orders():
while True:
do_this()
do_that()
return
async def create_order():
stop_loop_orders()
...
send_order()
resume_loop_orders()
return
我无法弄清楚这两个中的哪一个是要走的路:
- asyncio.Lock: 锁定了什么?我如何定义应该锁定的内容?
- asyncio.Event:wait() 方法将“等待事件设置。”=> 但我宁愿需要一个“等待 if 事件设置”功能。
我的第一个想法是
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()
所以在发送订单之前它设置 lock
所以 if not lock.locked():
应该跳过 do_this() do_that()
。但是代码可以 运行 在 do_this() do_that()
的某处然后 lock.locked()
无法阻止它。所以也许它应该在两者中
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()
这样当它开始发送时它必须等待do_this() do_that()
。当它开始时 do_this() do_that()
然后它必须等待 send_order()
顺便说一句:
如果你想理解它,那么在普通代码中它可能看起来像
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
顺便说一句:
我认为您可以以类似的方式使用 Event
,但您应该以不同的方式思考:您可以使用 wait if the event is **unset**/**clear**
wait if the event is set
您不能暂停和恢复异步任务。
您可以取消任务并稍后创建一个新任务,但这导致的问题多于解决的问题。数据一致性可能会受到影响,新任务将不会在前一个任务中断的地方恢复。
您可以轻松地让任务在某个特定点(或多个点)等待
async def loop_orders():
while True:
... wait here while paused ...
do_this()
do_that()
但是当 create_order
暂停 loop_orders
任务时,前者必须等到后者到达它暂停的那个点 - create_order
任务请求暂停并且 loop_orders
确认。
我用两个 Events
做了一个小演示,我将它们命名为 enable
和 idle
,试图使方法名称为 .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())
首先,我认为您或许应该考虑使用队列将其实现为 producer/consumer 模式。
但是如果你真的想暂停执行一个Task
,你可以看看这个