关于你的旧版(2.7)代码 - 多进程被认为是一个强大的替代品,可以同时处理CPU密集型任务,而线程模块则不太适用。你的代码可能不会受到CPU限制 - 因为它只需要进行HTTP请求 - 使用线程可能已经足以解决你的问题。
然而,Python 3+有一个很好的模块
concurrent.futures,通过酷炫的
Executor
类提供了更清晰的API,而不是直接使用
threading
。这个模块也可作为一个
外部包在python 2.7中使用。
以下代码适用于python 2和python 3:
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:
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))
这段代码使用基于线程的
futures.ThreadPoolExecutor
,其中很多魔法都在此处使用的
as_completed()
中。
你上面的 Python 3.6 代码使用了
run_in_executor()
,它创建了一个
futures.ProcessPoolExecutor()
,并没有真正使用异步 IO!!
如果你真的想使用 asyncio,你需要使用支持 asyncio 的 HTTP 客户端,比如
aiohttp。以下是一个示例代码:
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()
,现在使用真正的异步IO,在一个进程的一个线程上利用。
loop.run_until_complete()
调用坚定地位于异步代码路径之外。说实话,我会让main()
接受一个loop
参数,以便从loop.run_until_complete(main(loop))
传递。 - Martijn Pieters