【问题标题】:Python - How to cancel a specific task spawned by a nursery in python-trioPython - 如何取消由 python-trio 中的托儿所生成的特定任务
【发布时间】:2020-03-13 16:34:40
【问题描述】:

我有一个监听特定端口的异步函数。我想一次在几个端口上运行该函数,当用户想停止在特定端口上侦听时,停止在该端口上侦听的函数。

以前我使用 asyncio 库来执行此任务,我通过创建具有唯一 ID 作为名称的任务来解决此问题。

asyncio.create_task(Func(), name=UNIQUE_ID)

由于 trio 使用nurseries 来生成任务,我可以使用nursery.child_tasks 查看正在运行的任务,但这些任务无法命名它们,甚至无法按需取消任务

TL;DR

由于 trio 没有取消特定任务的 cancel() 函数,我该如何手动取消任务。

【问题讨论】:

    标签: python python-asyncio python-trio


    【解决方案1】:

    简单。您创建一个取消范围,从任务中返回它,并在需要时取消此范围:

    async def my_task(task_status=trio.TASK_STATUS_IGNORED):
        with trio.CancelScope() as scope:
            task_status.started(scope)
            pass  # do whatever
    
    async def main():
        async with trio.open_nursery() as n:
            scope = await n.start(my_task)
            pass  # do whatever
            scope.cancel()  # cancels my_task()
    

    神奇的部分是await n.start(task),它一直等到任务调用task_status.started(x) 并返回x 的值(或者None,如果你留空的话)。

    【讨论】:

    • 你能解释一下这段代码在做什么吗?我尝试阅读文档,但我仍然不知道它是如何工作的。也可以使用nursery.start_soon() 函数并仍然有cancel() 函数来取消子任务吗?
    • 要解释什么?你的任务在一个范围内运行,你可以取消范围,因此task_status.started() 通过await nursery.start 的结果将其传递回main,以便main 可以在需要时进行取消。
    • 您需要等到任务进行到创建范围并将句柄传回的地步。您当然可以使用共享对象和trio.Event 或其他任何方式手动完成所有这些操作,但是当 Trio 已经为您提供了一种内置的单行方式时,您为什么还要这样做呢?
    • 我也不明白。看起来正在启动的任务只是打开它以在某个时候取消,而不是从外部函数或事件随意取消。就像我使用 Trio 运行一个永远不会返回并永远运行的后台任务一样,当某个值变为 True 时,我该如何停止它?我一直在与 asyncio 一起使用 Trio 任务,当试图停止程序时,asyncio 会引发一个运行时错误,指出循环已经关闭。所以我只能sys.exit()os._exit(0) 否则三重奏部分将永远持续下去。我不认为我的方法是有效的。
    • 什么意思,怎么阻止?在某些时候,您的任务将调用 await trio.sleep() 或基本上任何其他异步 Trio 函数。此时,Trio 检查是否有人在它正在运行的任何取消范围上调用了cancel,如果是,它会引发trio.Cancelled 异常。不,您不能以这种方式将 trio 与 asyncio 一起使用。他们是不同的。 Trio 文档清楚地说明了这一点。如果您真的需要这样做,可以使用trio_asyncio
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多