![](/img/trans.png)
[英]How do I make async HTTP requests using httpx (VS requests) in Python?
[英]How do I make parallel async HTTP requests using httpx (versus aiohttp) in Python?
沒有刪除,因為它有 httpx 的示例代碼。
我正在嘗試利用asyncio
來並行化幾個長時間運行的 web 請求。 因為我是從requests
庫遷移的,所以我想使用httpx
庫,因為類似的 API。 我的環境是 Python 3.7.7 Anaconda 發行版,安裝了所有必需的軟件包(Windows 10)。
但是,盡管能夠將httpx
用於同步 web 請求(或用於串行執行一個接一個運行的異步請求),但我無法一次成功運行多個異步請求,盡管使用aiohttp
庫。
這是在aiohttp
中干凈運行的示例代碼:(請注意,我在 Jupyter 中運行,所以我已經有一個事件循環,因此缺少asyncio.run()
。
import aiohttp
import asyncio
import time
import httpx
async def call_url(session):
url = "https://services.cancerimagingarchive.net/services/v3/TCIA/query/getCollectionValues"
response = await session.request(method='GET', url=url)
#response.raise_for_status()
return response
for i in range(1,5):
start = time.time() # start time for timing event
async with aiohttp.ClientSession() as session: #use aiohttp
#async with httpx.AsyncClient as session: #use httpx
await asyncio.gather(*[call_url(session) for x in range(i)])
print(f'{i} call(s) in {time.time() - start} seconds')
這會產生預期的響應時間配置文件:
1 call(s) in 7.9129478931427 seconds
2 call(s) in 8.876991510391235 seconds
3 call(s) in 9.730034589767456 seconds
4 call(s) in 10.630006313323975 seconds
但是,如果我取消注釋async with httpx.AsyncClient as session: #use httpx
並注釋掉async with aiohttp.ClientSession() as session: #use aiohttp
(to swap in httpx
for aiohttp
) 然后我得到以下錯誤:
AttributeError Traceback (most recent call last)
<ipython-input-108-25244245165a> in async-def-wrapper()
17 await asyncio.gather(*[call_url(session) for x in range(i)])
18 print(f'{i} call(s) in {time.time() - start} seconds')
AttributeError: __aexit__
在我的在線研究中,我只能找到 Simon Hawe 的一篇 Medium 文章,展示了如何使用httpx
進行並行請求。 請參閱https://medium.com/swlh/how-to-boost-your-python-apps-using-httpx-and-asynchronous-calls-9cfe6f63d6ad
但是,示例異步代碼甚至不使用異步 session object 所以我剛開始有點懷疑。 該代碼不會在 Python 3.7.7 環境或 Jupyter 中執行。 (代碼在這里: https://gist.githubusercontent.com/Shawe82/a218066975f4b325e026337806f8c781/raw/3cb492e971c13e76a07d1a1e77b48de94aa7229cpy.con )
它導致此錯誤:
Traceback (most recent call last):
File ".\async_http_test.py", line 24, in <module>
asyncio.run(download_all_photos('100_photos'))
File "C:\Users\stborg\AppData\Local\Continuum\anaconda3\envs\fastai2\lib\asyncio\runners.py", line 43, in run
return loop.run_until_complete(main)
File "C:\Users\stborg\AppData\Local\Continuum\anaconda3\envs\fastai2\lib\asyncio\base_events.py", line 587, in run_until_complete
return future.result()
File ".\async_http_test.py", line 16, in download_all_photos
resp = await httpx.get("https://jsonplaceholder.typicode.com/photos")
TypeError: object Response can't be used in 'await' expression
我顯然做錯了什么,因為httpx
是為異步構建的。 我只是不確定它是什么!
好的。 坦率地說,這很尷尬。 無需解決方法。 在問題陳述中,我完全忽略了調用 AsyncClient 構造函數......我不敢相信我錯過了這么久。 天啊...
要修復,只需將缺少的括號添加到 AsyncClient 構造函數:
async with httpx.AsyncClient() as session: #use httpx
await asyncio.gather(*[call_url(session) for x in range(i)])
在進一步嘗試編寫此問題時,我發現httpx
和aiohttp
處理上下文管理器的方式存在細微差別。
在引入問題的代碼中,以下代碼與aiohttp
一起使用:
async with aiohttp.ClientSession() as session: #use aiohttp
await asyncio.gather(*[call_url(session) for x in range(i)])
此代碼將 ClientSession 上下文作為參數傳遞給call_url
方法。 我假設在asyncio.gather()
完成后,按照正常with
語句清理資源。
但是,與httpx
相同的方法失敗了,如上所述。 但是,這可以通過完全避免with
語句並手動關閉AsyncClient
來輕松解決。
換句話說,替換
async with httpx.AsyncClient as session: #use httpx
await asyncio.gather(*[call_url(session) for x in range(i)])
和
session = httpx.AsyncClient() #use httpx
await asyncio.gather(*[call_url(session) for x in range(i)])
await session.aclose()
解決問題。
這是完整的工作代碼:
import aiohttp
import asyncio
import time
import httpx
async def call_url(session):
url = "https://services.cancerimagingarchive.net/services/v3/TCIA/query/getCollectionValues"
response = await session.request(method='GET', url=url)
return response
for i in range(1,5):
start = time.time() # start time for timing event
#async with aiohttp.ClientSession() as session: #use aiohttp
session = httpx.AsyncClient() #use httpx
await asyncio.gather(*[call_url(session) for x in range(i)])
await session.aclose()
print(f'{i} call(s) in {time.time() - start} seconds')
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.