古い(2.7)コードに関して、マルチプロセッシングは、スレッド処理があまりうまくいかないCPU集約的なタスクを同時に処理する、より単純なスレッドモジュールの強力なドロップイン置換えとみなされます。あなたのコードはCPUに束縛されていない可能性があります.HTTPリクエストを作成するだけで済みますし、スレッドを使って問題を解決できるかもしれません。
threading
を直接使用する代わりに、Python 3+にはconcurrent.futuresという素晴らしいモジュールがあり、クールなExecutor
クラスを使用してよりクリーンなAPIを使用しています。このモジュールはPython 2.7のexternal packageとしても利用できます。
次のコードは、Python 2とPython 3で動作:このコードは、スレッドに基づいて、futures.ThreadPoolExecutor
を使用
# For python 2, first run:
#
# pip install futures
#
from __future__ import print_function
import requests
from concurrent import futures
URLS = [
'http://httpbin.org/delay/1',
'http://httpbin.org/delay/3',
'http://httpbin.org/delay/6',
'http://www.foxnews.com/',
'http://www.cnn.com/',
'http://europe.wsj.com/',
'http://www.bbc.co.uk/',
'http://some-made-up-domain.coooom/',
]
def fetch(url):
r = requests.get(url)
r.raise_for_status()
return r.content
def fetch_all(urls):
with futures.ThreadPoolExecutor(max_workers=5) as executor:
future_to_url = {executor.submit(fetch, url): url for url in urls}
print("All URLs submitted.")
for future in futures.as_completed(future_to_url):
url = future_to_url[future]
if future.exception() is None:
yield url, future.result()
else:
# print('%r generated an exception: %s' % (
# url, future.exception()))
yield url, None
for url, s in fetch_all(URLS):
status = "{:,.0f} bytes".format(len(s)) if s is not None else "Failed"
print('{}: {}'.format(url, status))
。ここでは多くの魔法がas_completed()
に使われています。
あなたのPython 3.6コードはrun_in_executor()
を使用してfutures.ProcessPoolExecutor()
を作成し、実際には非同期IOを使用しません!!
asyncioを実際に進めたい場合は、asyncioをサポートするHTTPクライアント(aiohttpなど)を使用する必要があります。今つのプロセスに一つだけのスレッドを利用して、実際の非同期IOを使用して、
import asyncio
import aiohttp
async def fetch(session, url):
print("Getting {}...".format(url))
async with session.get(url) as resp:
text = await resp.text()
return "{}: Got {} bytes".format(url, len(text))
async def fetch_all():
async with aiohttp.ClientSession() as session:
tasks = [fetch(session, "http://httpbin.org/delay/{}".format(delay))
for delay in (1, 1, 2, 3, 3)]
for task in asyncio.as_completed(tasks):
print(await task)
return "Done."
loop = asyncio.get_event_loop()
resp = loop.run_until_complete(fetch_all())
print(resp)
loop.close()
あなたが見ることができるように、asyncio
もas_completed()
があります。ここではサンプルコードです。
非同期コードブロック内のイベントループを入れないでください、非同期コードは、イベントループではなく、周りに他の方法で実行する必要があります。 –
ありがとう!確かに、私はここで何かを逃しています。私が見たすべてのイベントループの例では、loop.run_until_complete(get_api_results())を使用しています。これは、私の理解では、呼び出しをブロックして結果を失うことになります。 –
通常は、より多くのコルーチンが結果を処理し、それらを駆動するイベントループがあります。 –