【问题标题】:When using Python asyncio corurrent send network request, how to make coroutine prefer continue to handle response first, not send a new request?使用 Python asyncio corurrent 发送网络请求时,如何让协程优先继续处理响应,而不是发送新请求?
【发布时间】:2021-04-25 04:18:09
【问题描述】:

如果我想请求一个 API 1000 次(发送网络请求并处理响应),它将在发送所有 1000 个请求后开始处理响应,然后处理响应。

如果完成,我可以告诉 asyncio 更喜欢返回等待位置代码吗?

import asyncio

import httpx

# request_time = 10
request_time = 1000 # large enough to ensure previous responses return

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) # How to ensure return to run this code, not make a new request (run a new task `request_baidu` here)


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())

结果

# request_time = 10

===> 0
===> 1
===> 2
===> 3
===> 4
===> 5
===> 6
===> 7
===> 8
===> 9
<=== 3 # (we can see it continue to handle response after sending all request)
<=== 4
<=== 0 
<=== 1
<=== 2
<=== 5
<=== 6
<=== 7
<=== 8
<=== 9

预期结果:

===> 0
===> 1
<=== 0 #(continue handle response when there is some response)
===> 2
===> 3
<=== 1
<=== 2
===> 4
# ...

【问题讨论】:

    标签: python web-crawler python-asyncio coroutine httpx


    【解决方案1】:

    您可以使用asyncio.as_completed 获取最早的下一个结果:

    test.py:

    import asyncio
    import time
    
    from httpx import AsyncClient, Limits
    
    REQUESTS = 10
    URL = "http://www.baidu.com"
    TIMEOUT = 5
    
    
    async def request_baidu(client, i):
        t1 = time.process_time()
        print(f"===> {i}")
        r = await client.get(f"{URL}", timeout=TIMEOUT)
    
        return f"<=== {i} ({time.process_time() - t1:.3f}s)"
    
    
    async def main():
        async with AsyncClient() as client:
            aws = [asyncio.create_task(request_baidu(client, i)) for i in range(REQUESTS)]
    
            for coro in asyncio.as_completed(aws):
                earliest_result = await coro
                print(earliest_result)
    
    
    if __name__ == "__main__":
        asyncio.run(main())
    

    测试:

    $ python test.py
    ===> 0
    ===> 1
    ===> 2
    ===> 3
    ===> 4
    ===> 5
    ===> 6
    ===> 7
    ===> 8
    ===> 9
    <=== 9 (0.073s)
    <=== 2 (0.081s)
    <=== 1 (0.082s)
    <=== 0 (0.086s)
    <=== 8 (0.086s)
    <=== 4 (0.088s)
    <=== 6 (0.090s)
    <=== 3 (0.092s)
    <=== 7 (0.092s)
    <=== 5 (0.093s)
    

    【讨论】:

    • 非常感谢。我是 Python 异步编程的新手。这个问题困扰了我一晚上。昨天我学习到凌晨两点
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-04-09
    • 1970-01-01
    • 2011-01-12
    • 2015-01-06
    • 1970-01-01
    • 1970-01-01
    • 2021-12-18
    相关资源
    最近更新 更多