asyncio create_task()要排在队列的第一位吗?

时间:2019-07-25 10:25:28

标签: python python-asyncio asyncio

据我了解,当我调用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()尽快运行。

2 个答案:

答案 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.waitFIRST_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))