据我了解,当我调用create_task()
时,它将放在事件循环队列的末尾。
以下是我的用例,我有一些任务由相同的协程组成。我想取消某些失败情况下的所有任务。这是模式:
async def coro(params):
# long running task...
if failed_condition:
await cancel_all() # should cancel all tasks made of coro
async def cancel_all():
for task in tasks:
task.cancel()
await asyncio.gather(*tasks) # wait for cancel completion
print("All tasks cancelled")
tasks = []
async def main():
tasks = [loop.create_task(coro(params)) for x in range(5)]
asyncio.gather(*tasks)
问题在于,由于cancel_all()
本身正在等待一个任务,因此它自己被取消了。
我该如何解决?
我可以改用loop.create_task(cancel_all())
,但我希望cancel_all()尽快运行。
答案 0 :(得分:1)
cancel_all()
可以排除当前任务:
async def cancel_all():
to_cancel = set(tasks)
to_cancel.discard(asyncio.current_task())
for task in to_cancel:
task.cancel()
await asyncio.gather(*to_cancel)
答案 1 :(得分:0)
您可以将asyncio.wait与FIRST_EXCEPTION
参数一起使用。
import asyncio
import random
class UnexpectedCondition(Exception):
pass
async def coro(condition):
# long running task...
await asyncio.sleep(random.random()*10)
if condition:
raise UnexpectedCondition("Failed")
return "Result"
async def main(f):
tasks = [coro(f(x)) for x in range(5)]
done, pending = await asyncio.wait(tasks, return_when=asyncio.FIRST_EXCEPTION)
for p in pending:
# unfinished tasks will be cancelled
print("Cancel")
p.cancel()
for d in done:
try:
# get result from finished tasks
print(d.result())
except UnexpectedCondition as e:
# handle tasks with unexpected conditions
print(e)
asyncio.run(main(lambda x: x%2 == 0))