Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/vue.js/6.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python异步IO取消协同路由_Python_Python Asyncio - Fatal编程技术网

Python异步IO取消协同路由

Python异步IO取消协同路由,python,python-asyncio,Python,Python Asyncio,因此,给出了一个复杂的设置,用于生成半并行运行的查询列表(使用信号量以避免同时运行太多查询,从而避免对服务器进行DDoS攻击) 我有一个(本身是异步的)函数,可以创建许多查询: async def run_查询(self,url): 与self.semaphore异步: return wait some_http_lib(url) 异步def create_查询(自我、基本url): #…在实际环境中,收集逻辑要复杂一些 url=等待一些\u http\u lib(base\u url).jso

因此,给出了一个复杂的设置,用于生成半并行运行的查询列表(使用信号量以避免同时运行太多查询,从而避免对服务器进行DDoS攻击)

我有一个(本身是异步的)函数,可以创建许多查询:

async def run_查询(self,url):
与self.semaphore异步:
return wait some_http_lib(url)
异步def create_查询(自我、基本url):
#…在实际环境中,收集逻辑要复杂一些
url=等待一些\u http\u lib(base\u url).json()
coros=[self.run_查询url中的url]#注意:还没有执行
返回科罗斯
异步def执行_查询(自):
querys=等待self.create_查询('/seom/url'))
_info(f'prepared{len(querys)}querys')
结果=[]
完成=0
#注意:ofc,在这个简单的示例调用中,这些调用实际上不会异步执行。
#在我使用asyncio.gather的实际情况中,这只会稍微好一点
#可以理解的例子。
对于查询中的查询:
#此时,请求实际上被触发
结果=等待查询
#…一些后处理
如果没有结果['success']:
引发QueryException(结果['message'])#…内部异常
完成+=1
_info(f{len(查询)}查询完成}中的{done}
results.append(结果)
返回结果
现在,它工作得非常好,完全按照我的计划执行,我可以通过中止整个操作来处理其中一个查询中的异常

async def run():
尝试:
return wait QueryRunner.execute_querys()
除查询例外:
_logger.error('发生了可怕的错误')
一无所获
唯一的问题是程序被终止,但留给我的是通常的
运行时警告:coroutine QueryRunner.run\u查询从未等待过,因为队列中后面的查询(正确地)没有执行,因此也没有等待

有没有办法取消这些未等待的协同程序?否则是否有可能压制这一警告

[编辑]关于如何在这个简单示例之外执行查询的更多上下文: 查询通常分组在一起,因此有多个调用使用不同的参数创建_querys()。然后,所有收集的组都被循环,并使用asyncio.gather(group)执行查询。这将等待一个组的所有查询,但如果其中一个查询失败,其他组也将被取消,这将导致抛出错误。

使用

pending = asyncio.tasks.all_tasks()  # < 3.7 
以获取挂起任务的列表。你可以和我一起等他们

await asyncio.wait(pending, return_when=asyncio.ALL_COMPLETED)
或取消:

for task in pending:
    task.cancel()

因此,您询问如何取消尚未等待或传递给
聚集
的协同程序。有两种选择:

  • 您可以调用
    asyncio.create_task(c).cancel()
  • 您可以在上直接调用
    c.close()
第一个选项有点重(它创建一个任务只是为了立即取消它),但它使用了有文档记录的asyncio功能。第二个选项更轻量级,但也更低级

以上内容适用于从未转换为任务的协同路由对象(例如,通过将它们传递到
聚集
等待
)。如果它们有,例如,如果您调用了
asyncio.gather(*coros)
,其中一个已引发,并且您希望取消其余的,您应该更改代码,首先使用
asyncio.create_task()
将它们转换为任务,然后调用
gather
,最后使用
取消未完成的任务:

tasks = list(map(asyncio.create_task, coros))
try:
    results = await asyncio.gather(*tasks)
finally:
    # if there are unfinished tasks, that is because one of them
    # raised - cancel the rest
    for t in tasks:
        if not t.done():
            t.cancel()

wait self.create_querys(…)
看起来不可行,因为
create_querys()
返回的是一个列表,而不是一个可等待的对象。@user4815162342它返回一个协程列表。它们(通常)是通过asyncio.gather()连接的,但是为了这个示例,它们在execute_queries中的for循环中等待。哦,对了,我错过了
create_queries
本身是异步的。这只是给了我入口点的主要任务,而不是未等待的协程。取消它仍然会打印相同的RuntimeWarningi必须稍微更改收集逻辑以跟踪创建的协程,这在以前是不必要的。这样就可以像你建议的那样取消它们,事实上,效果很好。
tasks = list(map(asyncio.create_task, coros))
try:
    results = await asyncio.gather(*tasks)
finally:
    # if there are unfinished tasks, that is because one of them
    # raised - cancel the rest
    for t in tasks:
        if not t.done():
            t.cancel()