asyncio
で並列http要求タスクを実行したいのですが、python-requests
がasyncio
のイベントループをブロックすることがわかります。 aiohttp が見つかりましたが、httpプロキシを使用してhttp要求のサービスを提供できませんでした。
したがって、asyncio
の助けを借りて非同期http要求を行う方法があるかどうかを知りたいです。
Asyncioでリクエスト(または他のブロッキングライブラリ)を使用するには、 BaseEventLoop.run_in_executor を使用して別のスレッドで関数を実行し、そこから結果を取得します。例えば:
import asyncio
import requests
@asyncio.coroutine
def main():
loop = asyncio.get_event_loop()
future1 = loop.run_in_executor(None, requests.get, 'http://www.google.com')
future2 = loop.run_in_executor(None, requests.get, 'http://www.google.co.uk')
response1 = yield from future1
response2 = yield from future2
print(response1.text)
print(response2.text)
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
これにより、両方の応答が並行して取得されます。
python 3.5では、新しいawait
/async
構文を使用できます。
import asyncio
import requests
async def main():
loop = asyncio.get_event_loop()
future1 = loop.run_in_executor(None, requests.get, 'http://www.google.com')
future2 = loop.run_in_executor(None, requests.get, 'http://www.google.co.uk')
response1 = await future1
response2 = await future2
print(response1.text)
print(response2.text)
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
詳細については、 PEP0492 を参照してください。
aiohttp はすでにHTTPプロキシで使用できます:
import asyncio
import aiohttp
@asyncio.coroutine
def do_request():
proxy_url = 'http://localhost:8118' # your proxy address
response = yield from aiohttp.request(
'GET', 'http://google.com',
proxy=proxy_url,
)
return response
loop = asyncio.get_event_loop()
loop.run_until_complete(do_request())
上記の答えは、古いPython 3.4スタイルコルーチンを使用しています。 Python 3.5+を取得した場合の記述内容は次のとおりです。
aiohttp
サポート HTTPプロキシー
import aiohttp
import asyncio
async def fetch(session, url):
async with session.get(url) as response:
return await response.text()
async def main():
urls = [
'http://python.org',
'https://google.com',
'http://yifei.me'
]
tasks = []
async with aiohttp.ClientSession() as session:
for url in urls:
tasks.append(fetch(session, url))
htmls = await asyncio.gather(*tasks)
for html in htmls:
print(html[:100])
if __== '__main__':
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
現在、リクエストはasyncio
をサポートしていません。そのようなサポートを提供する予定はありません。 asyncio
の使用方法を知っているカスタムの "Transport Adapter"( here )を実装できる可能性があります。
しばらくして自分自身を見つけた場合、実際に検討するかもしれませんが、何も約束できません。
Pimin Konstantin Kefaloukosの記事には、非同期/待機ループとスレッドの良いケースがあります Pythonとasyncioを使用した簡単な並列HTTP要求 :
合計完了時間を最小限に抑えるために、スレッドプールのサイズを増やして、必要な要求の数に一致させることができます。幸いなことに、これは次のように簡単に実行できます。以下のコードリストは、20個のワーカースレッドのスレッドプールで20個の非同期HTTP要求を作成する方法の例です。
# Example 3: asynchronous requests with larger thread pool
import asyncio
import concurrent.futures
import requests
async def main():
with concurrent.futures.ThreadPoolExecutor(max_workers=20) as executor:
loop = asyncio.get_event_loop()
futures = [
loop.run_in_executor(
executor,
requests.get,
'http://example.org/'
)
for i in range(20)
]
for response in await asyncio.gather(*futures):
pass
loop = asyncio.get_event_loop()
loop.run_until_complete(main())