1. 多线程URL处理的必要性
在数据处理和网络爬虫开发中,我们经常需要处理大量URL请求。假设我们有一个包含1000个URL的列表,每个URL需要执行以下操作:
- 发送HTTP请求获取页面内容
- 解析页面提取关键数据
- 将结果存储到数据库
使用传统的单线程方式,代码可能如下:
python复制def process_url(url):
# 模拟网络请求和数据处理
response = requests.get(url)
data = parse_response(response)
save_to_database(data)
for url in url_list:
process_url(url)
这种方式的效率瓶颈非常明显:网络I/O等待时间占据了大部分处理时间。当单个请求需要500ms时,1000个URL就需要500秒(约8分钟)才能完成。
关键理解:网络请求属于I/O密集型操作,CPU在等待响应时处于空闲状态。多线程的核心价值就是利用这些等待时间来处理其他任务。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. Python线程池实战实现
2.1 ThreadPoolExecutor基础用法
Python的concurrent.futures模块提供了高级的线程池接口:
python复制from concurrent.futures import ThreadPoolExecutor
import time
def worker(url):
print(f"开始处理 {url}")
start = time.time()
process_url(url) # 实际处理函数
cost = time.time() - start
print(f"完成 {url} [耗时:{cost:.2f}s]")
with ThreadPoolExecutor(max_workers=5) as executor:
for url in url_list:
executor.submit(worker, url)
这里有几个关键点需要注意:
- max_workers控制并发线程数,通常设置为CPU核心数的2-5倍
- submit方法将任务加入线程池队列
- with语句确保线程池正确关闭
2.2 进阶错误处理机制
实际生产中我们需要更健壮的错误处理:
python复制def safe_worker(url):
try:
worker(url)
except requests.exceptions.RequestException as e:
print(f"请求失败 {url}: {str(e)}")
except DatabaseError as e:
print(f"数据库错误 {url}: {str(e)}")
except Exception as e:
print(f"未知错误 {url}: {str(e)}")
def retry_worker(url, max_retries=3):
for attempt in range(max_retries):
try:
return worker(url)
except Exception as e:
if attempt == max_retries - 1:
raise
w
