web-dev-qa-db-ja.com

非同期でリクエストを使用するにはどうすればよいですか?

asyncioで並列http要求タスクを実行したいのですが、python-requestsasyncioのイベントループをブロックすることがわかります。 aiohttp が見つかりましたが、httpプロキシを使用してhttp要求のサービスを提供できませんでした。

したがって、asyncioの助けを借りて非同期http要求を行う方法があるかどうかを知りたいです。

110
flyer

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 を参照してください。

163
christian

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

上記の答えは、古い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())
23
ospider

現在、リクエストはasyncioをサポートしていません。そのようなサポートを提供する予定はありません。 asyncioの使用方法を知っているカスタムの "Transport Adapter"( here )を実装できる可能性があります。

しばらくして自分自身を見つけた場合、実際に検討するかもしれませんが、何も約束できません。

9
Lukasa

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