本文目录导读:

- 使用
asyncio.Semaphore(异步场景) - 使用
concurrent.futures.ThreadPoolExecutor(多线程场景) - 使用队列 + 消费者模式(生产消费模型)
- 使用第三方库
ratelimit或throttle - 分布式场景:使用 Redis 实现分布式锁或队列
- 最佳实践建议
在Python中避免同步任务扎堆执行,核心思路是控制并发数和防止任务堆积,以下是几种常见场景的解决方案:
使用 asyncio.Semaphore(异步场景)
当使用 asyncio 时,信号量可以限制同时执行的任务数:
import asyncio
import aiohttp
async def worker(sem, url):
async with sem: # 获取信号量,如果已满则等待
async with aiohttp.ClientSession() as session:
async with session.get(url) as resp:
data = await resp.text()
print(f"处理 {url}: 长度 {len(data)}")
await asyncio.sleep(0.1) # 模拟其他耗时操作
async def main():
sem = asyncio.Semaphore(5) # 最多5个任务同时执行
urls = [f"https://httpbin.org/get?id={i}" for i in range(100)]
# 创建所有任务但会通过信号量控制并发
tasks = [worker(sem, url) for url in urls]
await asyncio.gather(*tasks)
asyncio.run(main())
使用 concurrent.futures.ThreadPoolExecutor(多线程场景)
限制线程池大小来避免扎堆:
from concurrent.futures import ThreadPoolExecutor, as_completed
import time
import random
def task(item):
"""模拟一个耗时的同步任务"""
delay = random.uniform(0.1, 0.5)
time.sleep(delay)
return f"任务 {item} 完成, 耗时 {delay:.2f}s"
# 控制并发数:最多3个线程同时执行
with ThreadPoolExecutor(max_workers=3) as executor:
# 提交任务,不会立即阻塞
futures = {executor.submit(task, i): i for i in range(20)}
# 按完成顺序获取结果
for future in as_completed(futures):
item = futures[future]
try:
result = future.result()
print(result)
except Exception as e:
print(f"任务 {item} 失败: {e}")
使用队列 + 消费者模式(生产消费模型)
适用于任务生成速度可能超过处理速度的场景:
from queue import Queue
from threading import Thread
import time
import random
class TaskConsumer:
def __init__(self, num_workers=3, max_queue_size=20):
self.queue = Queue(maxsize=max_queue_size) # 限制队列大小
self.num_workers = num_workers
self.workers = []
def start(self):
for i in range(self.num_workers):
t = Thread(target=self._worker, args=(i,), daemon=True)
t.start()
self.workers.append(t)
def _worker(self, worker_id):
while True:
try:
task = self.queue.get(timeout=5) # 5秒超时退出
print(f"Worker {worker_id}: 开始处理 {task}")
time.sleep(random.uniform(0.2, 0.8)) # 模拟处理时间
print(f"Worker {worker_id}: 完成 {task}")
self.queue.task_done()
except:
break # 超时退出
def add_task(self, task):
"""添加任务,如果队列已满会阻塞"""
self.queue.put(task) # 如果队列满,这里会等待
print(f"添加任务 {task}, 当前队列大小: {self.queue.qsize()}")
# 使用示例
consumer = TaskConsumer(num_workers=3, max_queue_size=10)
consumer.start()
# 模拟快速生成任务
for i in range(100):
consumer.add_task(f"任务_{i}")
time.sleep(0.05) # 控制生成速度
print("所有任务已提交")
consumer.queue.join() # 等待所有任务完成
使用第三方库 ratelimit 或 throttle
控制执行频率:
from ratelimit import limits, sleep_and_retry
import time
@sleep_and_retry
@limits(calls=5, period=1) # 每秒最多5次调用
def limited_function(item):
print(f"执行: {item}")
time.sleep(0.3)
# 即使快速循环,也会被限速
for i in range(50):
limited_function(i)
分布式场景:使用 Redis 实现分布式锁或队列
import redis
import time
import random
r = redis.Redis(host='localhost', port=6379, db=0)
def process_with_redis_queue(task_id):
"""从Redis列表取任务,最多同时处理5个"""
# 如果活跃任务超过限制,等待
while r.llen(f"active_tasks:worker_{task_id}") >= 5:
print("等待中...")
time.sleep(0.5)
# 模拟处理
print(f"处理任务 {task_id}")
r.lpush(f"active_tasks:worker_{task_id}", task_id)
time.sleep(random.uniform(0.5, 2))
r.lrem(f"active_tasks:worker_{task_id}", 0, task_id)
print(f"完成任务 {task_id}")
# 多个worker可以独立运行
for i in range(20):
process_with_redis_queue("worker_1")
最佳实践建议
-
明确瓶颈类型:
- CPU密集 → 使用
ProcessPoolExecutor - IO密集 → 使用
ThreadPoolExecutor或asyncio - 外部服务限制 → 使用信号量 + 限速
- CPU密集 → 使用
-
监控任务堆积:
import logging from queue import Queue class MonitoredQueue(Queue): def put(self, item, block=True, timeout=None): if self.qsize() > self.maxsize * 0.8: logging.warning(f"队列接近满: {self.qsize()}/{self.maxsize}") super().put(item, block, timeout) -
动态调整并发数:
class AdaptiveExecutor: def __init__(self, min_workers=2, max_workers=10): self.min_workers = min_workers self.max_workers = max_workers self.current_workers = min_workers def adjust_workers(self, queue_size, processing_time): if queue_size > 50 and processing_time < 0.1: self.current_workers = min(self.max_workers, self.current_workers + 1) elif queue_size < 10 and self.current_workers > self.min_workers: self.current_workers -= 1
选择哪种方案取决于你的具体场景:
- 异步IO操作 →
asyncio.Semaphore - 同步阻塞操作 →
ThreadPoolExecutor或队列 - 需要跨进程/跨机器 → Redis队列或消息队列(如 RabbitMQ)
- 严格控制调用频率 →
ratelimit库
需要根据实际业务特点和性能要求来选择或组合使用这些策略。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播