Python 从已取消的任务中获取结果

Python 从已取消的任务中获取结果,python,python-asyncio,Python,Python Asyncio,我有一个程序,大致像下面的例子。 任务是收集多个值并将其返回给调用方。 有时任务可能会被取消。 在这些情况下,我仍然希望得到任务到目前为止收集到的结果。 因此,我捕获cancelederror异常,清理并返回完成的结果 async def f(): results = [] for i in range(100): try: res = await slow_call() results.append(res)

我有一个程序,大致像下面的例子。 任务是收集多个值并将其返回给调用方。 有时任务可能会被取消。 在这些情况下,我仍然希望得到任务到目前为止收集到的结果。 因此,我捕获
cancelederror
异常,清理并返回完成的结果

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()
只需重新调用
cancelederror
。调用
task.\u result
只是
None

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

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


有什么好方法的建议吗?

我认为这是不可能的,因为在我看来,这与取消任务的含义相冲突。
您可以在slow_调用中实现类似的行为,方法是触发CanceledError,在函数中捕获它,然后返回您想要的任何结果。

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

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())
导入异步IO
异步def fn(结果):
对于范围(10)内的i:
#你的慢电话
等待异步睡眠(0.1)
结果.附加(i)
def on_已完成(任务、结果):
如果任务已取消():
打印(“不完整”,结果)
其他:
打印(“完成”,结果)
异步def run():
结果=[]
task=asyncio.create_任务(fn(结果))
task.add_done_回调(lambda t:on_done(t,results))
#给fn一些时间来完成,减少时间会导致任务取消
#如果小于1.1,您将看到不完整的消息
等待异步睡眠(1.1)
asyncio.run(run())

run
中使用
add\u done\u callback
sleep
,感觉非常尴尬,让我觉得我不明白你在做什么。也许发布一些包含更多调用代码的内容将有助于找到更好的方法来组织事情。请注意,与
asyncio
builtin库(在IMO中是过早标准化的)相比,还有其他类似的库为Python协同程序提供了更好的接口。问题是我返回的值被丢弃了。可以肯定,被取消的
任务
也会导致未来被取消。无论任务是否“失败”,这都会导致将来出现一个
取消错误
。也许任务可以通过把它们推到一个“.sasason”中来“返回”价值,我确实考虑过用队列来处理所有的事情。这似乎与任务的理念背道而驰,首先要有
result()
s。这取决于您所追求的API。一般来说,人们只关心完成一项定义明确的“任务”,但在这里,你的任务是做很多事情,部分结果是有用的。因此,在这种情况下,使用队列似乎更合适。请注意,您也可以将
列表
传递给
f
,并将结果附加到列表中。您需要某种方法使此列表在完成时
。队列可以让您在添加中间结果时获得中间结果,而不只是等待任务“完成”,这完全取决于什么样的抽象更合适!为什么您使用的是
add\u done\u callback
而不是
等待任务?
asyncio
的最大优点之一是摆脱了以前存在的“回调地狱”,例如在TwistedPython中。@SamMason这是因为我有很多任务。我试图使用
asyncio.wait()
,但我希望它在任务完成或抛出错误时返回。目前看来,您必须选择等待哪种条件,因此我必须在完成时使用
:(