asyncio 协程并发发送网络请求,如何优先继续处理返回结果的任务,而不是开始发送新的请求?

2021-04-25 10:49:37 +08:00
 LudwigWS
import asyncio

import httpx

request_time = 10

limits = httpx.Limits(max_connections=5)
client = httpx.AsyncClient(limits=limits)


async def request_baidu(i):
    # async with httpx.AsyncClient(limits=limits) as client:
        print(f"===> %d" % i)
        r = await client.get("http://www.baidu.com")
        # print(r.status_code)
        print(f"<=== %d" % i) # 如何保证优先执行此处代码,而不发送新的请求?


async def main():
    request_list = [asyncio.create_task(request_baidu(i)) for i in range(request_time)]
    await asyncio.gather(*request_list)

if __name__ == '__main__':
    asyncio.run(main())

"""
===> 0
===> 1
===> 2
===> 3
===> 4
===> 5
===> 6
===> 7
===> 8
===> 9
<=== 3
<=== 4
<=== 0 # 可以看到发送完所有的网络请求,才开始处理返回的结果
<=== 1
<=== 2
<=== 5
<=== 6
<=== 7
<=== 8
<=== 9

期望的结果:
===> 0
===> 1
<=== 0 # 在前面的请求放回结果的时候优先返回该处继续向下执行,而不是发送新的请求
===> 2
===> 3
<=== 1
<=== 2
===> 4
...
"""
1173 次点击
所在节点    Python
5 条回复
linw1995
2021-04-25 12:33:20 +08:00
主因是这个服务响应得太快。如果我没理解错你的诉求的话,你期望的没法简单的实现。你这个例子可分解成,做网络请求,再对响应内容作处理。看 asyncio loop._run_once 的源码,你可以发现 IO 事件是优先执行的。你想优先处理非 IO 事件的协程,只能串行执行了。

那可以这样,先处理所有 响应内容,再做一次请求

```python
def handle_loop(q_request, q_response):
while True:
await handle_response(q_response) # 执行全部
await handle_request(q_request) # 执行一个
```

以上就是本人粗略判断得出来的结论
LudwigWS
2021-04-25 13:09:44 +08:00
@linw1995 感谢,我研究一下源码和考虑一下其他写法。昨天研究了一个晚上,折腾到凌晨两点都没想明白😂
ClericPy
2021-04-25 20:54:26 +08:00
你描述的场景... 是要把并发改串行吗, 一时间没看懂需求

就字面意思, 能想到的就是 asyncio.Semophare, asyncio.Lock 之类的
LudwigWS
2021-04-25 22:27:08 +08:00
@ClericPy 还是并发,但是要求如果有响应就处理响应的结果,现在是发送完所有的请求再返回处理响应了,等于前面的结果一直阻塞等到最后才被处理
0x0208v0
2021-04-28 15:52:47 +08:00
最后你是怎么解决的?

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/773059

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX