一种Pythonic方式,用于更改应从调用cancel()的位置取消异步任务的方式

前端之家收集整理的这篇文章主要介绍了一种Pythonic方式,用于更改应从调用cancel()的位置取消异步任务的方式 前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

如何从取消任务的位置更改取消任务的行为?

我梦dream以求的:

task = ensure_future(foo())

def foo_done(task)
    try:
        return task.get_result()
    except CancelError as e:
        when,why = e.args
        if when == "now"
            # do something...
        elif when == "asap":
            # do something else...
        else:
            # do default
        print(f"task cancelled because {why}")

task.add_done_callback(foo_done)

[...]

task.cancel("now","This is an order!")

我可以在调用task.cancel()之前将对象附加到任务,然后再检查它.

task = ensure_future(foo())

def foo_done(task)
    try:
        return task.get_result()
    except CancelError as e:
        when = getattr(task,"_when","")
        why = getattr(task,"_why","")
        if when == "now"
            # do something...
        elif when == "asap":
            # do something else...
        else:
            # do default
        print(f"task cancelled because {why}")

task.add_done_callback(foo_done)

[...]
task._when = "now"
task._why = "This is an order!"
task.cancel()

但是在某些情况下,例如当我想捕获正在执行的任务中的CancelError时,它看起来很笨拙:

async def foo():
   # some stuff
   try:
       # some other stuff
   except CancellError as e:
       # here I have easily access to the error,but not the task :(
   [...]

我正在寻找一种更Python化的方式来做到这一点.

最佳答案
用与异常相关的数据装饰任务的解决方案实际上是一个很好的解决方案.在任务内,您可以使用asyncio.Task.current_task()访问正在处理的任务.

您还可以使用以下装饰器(未经测试)实现您梦dream以求的语法:

def propagate_when(fn):
    async def wrapped(*args,**kwds):
        try:
            return await fn(*args,**kwds)
        except CancelledError as e:
            e.when = getattr(asyncio.Task.current_task(),'_when',None)
            raise
    return wrapped

在处理CancelledError时,使用@propagate_when装饰协程可允许foo_done中的代码访问e.when.缺点是e.when在任务内不可用时-您仍然必须使用current_task().由于存在这种不一致,我建议坚持从任务对象读取.

几个相关的建议:

>将取消代码放入存储您传递的对象的实用程序函数中,然后调用task.cancel().这种封装的薄层应该从当前代码中消除“笨拙”的感觉.
>使用带前缀的属性名称-简短而通用的名称,例如_when会在将来的版本中引起冲突. (我知道这只是一个例子,但未加前缀的名称始终有发生冲突的危险.)
>用单个对象装饰任务,将实际数据放入其属性.它使检索变得更简单,更干净,并且使您可以选择在存储的对象上实现方法.

原文链接:https://www.f2er.com/python/533129.html

猜你在找的Python相关文章