我有一个程序,大致类似于下面的示例。
一项任务是收集许多值并将其返回给调用方。
有时,任务可能会被取消。
在那些情况下,我仍然想获得到目前为止任务已收集的结果。
因此,我捕获了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
导致任务根本没有被取消。
这给我带来了另一个难题:我如何向任务所有者发出信号,该结果只是一个“一半”的结果,而任务实际上已被取消。
我想我可以添加一个额外的返回值来表明这一点,但这似乎与任务取消系统的整个想法背道而驰。
这里有什么好的方法建议吗?
答案 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
中使用sleep
和run
感到很尴尬,让我觉得我不明白您在做什么。也许将包含更多调用代码的内容发布到https://codereview.stackexchange.com上将有助于获得构筑事物的更好方法的想法。请注意,还有其他类似trio的库,它们提供了比asyncio
内置库(IMO早已标准化)更好的Python协程接口。
答案 1 :(得分:0)
我认为这是不可能的,因为我认为这与取消任务的含义相冲突。 您可以通过触发CancelledError,在函数中捕获它,然后返回所需的内容,来在slow_call中实现类似的行为。