实用指南
在Web开发或数据抓取过程中,我们经常需要同时向多个服务器发送HTTP请求。Python提供了多种方法来实现并发请求,从而提高程序的执行效率。本文将介绍几种实用的并发请求技术,并给出示例代码。
1. 使用threading
模块
Python的threading
模块允许我们创建多线程程序。然而,由于Python的全局解释器锁(GIL),多线程在CPU密集型任务上可能并不会带来性能提升。但在I/O密集型任务(如网络请求)上,多线程仍然是一个有效的选择。
示例代码:
import threading
import requests
def fetch_url(url):
response = requests.get(url)
print(f"Got response from {url}: {response.status_code}")
urls = [
'http://example.com/1',
'http://example.com/2',
# ... 更多URL
]
threads = []
for url in urls:
t = threading.Thread(target=fetch_url, args=(url,))
t.start()
threads.append(t)
# 等待所有线程完成
for t in threads:
t.join()
2. 使用asyncio
和aiohttp
对于异步编程,Python 3.5及以上版本引入了asyncio
库。aiohttp
是一个基于asyncio
的HTTP客户端/服务器库,非常适合并发请求。
示例代码:
import asyncio
import aiohttp
async def fetch_url(session, url):
async with session.get(url) as response:
print(f"Got response from {url}: {response.status}")
async def main():
async with aiohttp.ClientSession() as session:
tasks = []
urls = [
'http://example.com/1',
'http://example.com/2',
# ... 更多URL
]
for url in urls:
task = asyncio.create_task(fetch_url(session, url))
tasks.append(task)
# 等待所有任务完成
await asyncio.gather(*tasks)
# Python 3.7+ 可以用下面的方式运行main函数
asyncio.run(main())
3. 使用concurrent.futures
concurrent.futures
模块提供了高级接口,用于异步执行可调用对象。ThreadPoolExecutor
用于多线程,而ProcessPoolExecutor
用于多进程(但请注意,多进程在I/O密集型任务上可能不如多线程有效,且存在更多的开销)。
示例代码(使用ThreadPoolExecutor
):
import concurrent.futures
import requests
def fetch_url(url):
response = requests.get(url)
print(f"Got response from {url}: {response.status_code}")
urls = [
'http://example.com/1',
'http://example.com/2',
# ... 更多URL
]
with concurrent.futures.ThreadPoolExecutor(max_workers=5) as executor:
futures = {executor.submit(fetch_url, url): url for url in urls}
for future in concurrent.futures.as_completed(futures):
url = futures[future]
try:
# 如果fetch_url抛出异常,则捕获它
data = future.result()
except Exception as exc:
print(f'Generated an exception for {url}: {exc}')
注意事项:
- 在并发请求时,请确保遵守目标网站的robots.txt文件和服务条款,避免对服务器造成过大的负载。
- 并发请求可能会增加网络带宽的使用,请确保您的网络环境可以支持这种使用模式。
- 不同的并发策略在不同的应用场景下可能有不同的效果,请根据您的实际需求选择合适的策略。