【发布时间】:2019-05-16 01:42:26
【问题描述】:
关键问题:asyncio.wait(aws,timeout=1,return_when=FIRST_COMPLETED) 有没有简单的方法可以检查返回的任务是否超时?
这是一个扩展问题。
场景是这样的:
- 协程总数未知
- 服务器只允许 10 个链接
- 服务器会返回一个看似正确的结果(例如返回一个不正确的页面)
- 服务器有时不返回任何数据。
- 最大可能访问所有数据
所以为了更快的获取数据,我需要限制协程的数量。检查返回的页面。并超时。
目前有两种简单的方法。
1.类似线程,使用queue搭建协程池+10个无限循环coro。我真的不喜欢它。事实上,这种方法效果非常好。
2.我尝试使用async python3.7的高级API,尽量简化程序结构,使用while tasks&asyncio.wait&return_when。
在这里,我遇到了如何查找协程超时的问题。
我构建了一个简单的演示:
import asyncio
async def test(delaytime):
print(f"begin {delaytime}")
await asyncio.sleep(delaytime )
print(f"finish {delaytime} ")
async def main():
# the number of tasks is unknow,range(10) is just a demo
allts = list(range(10))
ts = []
while len(ts)<5:
arg = allts.pop()
t = asyncio.create_task(test(arg))
t.arg = arg
ts.append(t)
while ts:
dones,pendings = await asyncio.wait(ts,timeout=2,return_when=asyncio.FIRST_COMPLETED)
for t in dones:
# if check t.result() is error , i can append ts again
print(t.arg,"is done")
ts.remove(t)
while len(ts)<5:
if len(allts):
arg = allts.pop()
t = asyncio.create_task(test(arg))
t.arg = arg
ts.append(t)
else:
break
# for t in pendings:
# # if can check t is timeout , i can append ts again
# pass
if __name__=="__main__":
asyncio.run(main())
调试后知道return_when=asyncio.FIRST_COMPLETED,asyncio.wait返回的任务都在pending中,除了已完成的任务。
但是,我不知道哪个任务超时。
我考虑过使用wait_for,但wait_for 没有return_when 参数。
有没有简单的方法来确定超时任务以便重新加入ts?
【问题讨论】:
-
因为它是异步的,所以逻辑是要么发出信号,要么留下痕迹。最简单的方法可能是写入日志文件,您应该一直这样做。
-
尝试检查
t.exception()。此外,它是“待定”,而不是“待定”。 -
@user4815162342
t.exception()无效,所有待处理的任务都显示Exception is not set.,实际上是一个asyncio.InvalidStateError。无法判断待处理的任务是否已超时。抱歉,我的拼写错误。 -
答案中的方法是否适用于您的情况?
-
@user4815162342 你的回答很有用,谢谢!尽管我仍然认为这种用法很丑陋。但是仅仅使用 asyncio 的高级 API,这可能是最好的编写方式。除了上面提到的
queue和wait(FIRST_COMPLETED),这个场景还有其他pythonic的想法吗?
标签: python python-asyncio