从取消的任务中获取结果

时间:2019-08-28 12:10:44

标签: python python-asyncio

我有一个程序,大致类似于下面的示例。 一项任务是收集许多值并将其返回给调用方。 有时,任务可能会被取消。 在那些情况下,我仍然想获得到目前为止任务已收集的结果。 因此,我捕获了CancelledError异常,清理并返回完成的结果。

async def f():
    results = []
    for i in range(100):
        try:
            res = await slow_call()
            results.append(res)
        except asyncio.CancelledError:
            results.append('Undecided')
    return results

def on_done(task):
    if task.cancelled():
        print('Incomplete result', task.result()
    else:
        print(task.result())

async def run():
    task = asyncio.create_task(f())
    task.add_done_callback(on_done)

问题是任务取消后返回的值似乎在任务中不可用。 调用task.result()只会重新抛出CancelledError。呼叫task._result就是None

假设有一个任务,有没有办法获取已取消任务的返回值?

编辑:我现在意识到,捕获CancelledError导致任务根本没有被取消。 这给我带来了另一个难题:我如何向任务所有者发出信号,该结果只是一个“一半”的结果,而任务实际上已被取消。 我想我可以添加一个额外的返回值来表明这一点,但这似乎与任务取消系统的整个想法背道而驰。

这里有什么好的方法建议吗?

2 个答案:

答案 0 :(得分:1)

我距离理解用例还有很长的路要走,但是以下内容对我来说很有意义:

import asyncio

async def fn(results):
    for i in range(10):
        # your slow_call
        await asyncio.sleep(0.1)
        results.append(i)

def on_done(task, results):
    if task.cancelled():
        print('incomplete', results)
    else:
        print('complete', results)

async def run():
    results = []
    task = asyncio.create_task(fn(results))
    task.add_done_callback(lambda t: on_done(t, results))
    # give fn some time to finish, reducing this will cause the task to be cancelled
    # you'll see the incomplete message if this is < 1.1
    await asyncio.sleep(1.1)

asyncio.run(run())

add_done_callback中使用sleeprun感到很尴尬,让我觉得我不明白您在做什么。也许将包含更多调用代码的内容发布到https://codereview.stackexchange.com上将有助于获得构筑事物的更好方法的想法。请注意,还有其他类似trio的库,它们提供了比asyncio内置库(IMO早已标准化)更好的Python协程接口。

答案 1 :(得分:0)

我认为这是不可能的,因为我认为这与取消任务的含义相冲突。 您可以通过触发CancelledError,在函数中捕获它,然后返回所需的内容,来在slow_call中实现类似的行为。