本文目录导读:

- 基础方案:asyncio.gather
- 控制并发数:Semaphore信号量
- 使用asyncio.TaskGroup (Python 3.11+)
- 生产级方案:完整的任务队列系统
- 极简方案:使用asyncio.Queue
我来详细介绍Python中实现协程批量任务执行的几种常用方法。
基础方案:asyncio.gather
import asyncio
import time
from typing import List, Any
async def task(name: str, delay: float) -> str:
"""模拟异步任务"""
print(f"开始执行任务: {name}")
await asyncio.sleep(delay)
print(f"任务完成: {name}")
return f"{name} 的结果"
async def batch_execute_gather():
"""使用gather批量执行"""
tasks = []
for i in range(5):
tasks.append(task(f"任务{i}", i * 0.5))
# 同时执行所有任务
results = await asyncio.gather(*tasks)
print(f"所有任务完成: {results}")
return results
# 运行
asyncio.run(batch_execute_gather())
控制并发数:Semaphore信号量
import asyncio
import aiohttp
from typing import List
class BatchExecutor:
def __init__(self, max_concurrency: int = 3):
self.semaphore = asyncio.Semaphore(max_concurrency)
async def limited_task(self, task_id: int, url: str) -> dict:
"""带并发限制的任务执行"""
async with self.semaphore:
print(f"开始任务 {task_id},当前并发: {self.semaphore._value}")
try:
async with aiohttp.ClientSession() as session:
async with session.get(url) as response:
return await response.json()
except Exception as e:
print(f"任务 {task_id} 失败: {e}")
return None
finally:
print(f"完成任务 {task_id}")
async def execute_batch(self, tasks: List[tuple]) -> List[Any]:
"""批量执行带并发控制的任务"""
coroutines = [
self.limited_task(task_id, url)
for task_id, url in tasks
]
return await asyncio.gather(*coroutines)
# 并行执行带限制的HTTP请求
async def main():
executor = BatchExecutor(max_concurrency=2)
tasks = [
(1, "http://example.com/api/1"),
(2, "http://example.com/api/2"),
(3, "http://example.com/api/3"),
(4, "http://example.com/api/4"),
]
results = await executor.execute_batch(tasks)
print(f"最终结果: {results}")
# asyncio.run(main())
使用asyncio.TaskGroup (Python 3.11+)
import asyncio
from typing import List
class AdvancedBatchExecutor:
async def process_item(self, item: dict) -> dict:
"""处理单个项目"""
await asyncio.sleep(0.1) # 模拟IO操作
return {"processed": item["id"], "result": item["value"] * 2}
async def batch_process(self, items: List[dict]) -> List[dict]:
"""使用TaskGroup批量处理"""
results = []
# Python 3.11+ 的 TaskGroup
async with asyncio.TaskGroup() as tg:
# 创建任务并保存引用
tasks = [tg.create_task(self.process_item(item)) for item in items]
# 等待所有任务完成(自动管理异常)
# TaskGroup会自动等待所有任务
# 收集结果
results = [task.result() for task in tasks]
return results
# 使用示例
async def main():
executor = AdvancedBatchExecutor()
items = [
{"id": i, "value": i * 10}
for i in range(10)
]
results = await executor.batch_process(items)
print(f"处理结果: {results}")
# asyncio.run(main())
生产级方案:完整的任务队列系统
import asyncio
import logging
from typing import Callable, Any, List
from dataclasses import dataclass
from datetime import datetime
@dataclass
class TaskResult:
task_id: str
status: str # 'success', 'failed'
result: Any = None
error: str = None
class BatchTaskManager:
def __init__(self,
max_concurrency: int = 5,
retry_times: int = 3):
self.semaphore = asyncio.Semaphore(max_concurrency)
self.retry_times = retry_times
self.logger = logging.getLogger(__name__)
async def execute_with_retry(self,
task_func: Callable,
task_id: str,
*args,
**kwargs) -> TaskResult:
"""带重试机制的任务执行"""
for attempt in range(self.retry_times):
try:
async with self.semaphore:
self.logger.info(f"执行任务 {task_id}, 第{attempt+1}次尝试")
result = await task_func(*args, **kwargs)
return TaskResult(
task_id=task_id,
status='success',
result=result
)
except Exception as e:
self.logger.error(f"任务 {task_id} 第{attempt+1}次失败: {e}")
if attempt == self.retry_times - 1:
return TaskResult(
task_id=task_id,
status='failed',
error=str(e)
)
await asyncio.sleep(1 * (attempt + 1)) # 退避等待
async def process_batch(self,
tasks: List[tuple],
progress_callback: Callable = None) -> List[TaskResult]:
"""批量处理任务"""
tasks_list = []
total = len(tasks)
for i, (task_id, task_func, args, kwargs) in enumerate(tasks):
task = self.execute_with_retry(task_func, task_id, *args, **kwargs)
tasks_list.append(task)
# 使用as_completed获取任务进度
results = []
completed = 0
for coro in asyncio.as_completed(tasks_list):
result = await coro
results.append(result)
completed += 1
if progress_callback:
progress_callback(completed, total, result)
return results
# 使用示例
async def example_task(task_id: str, data: dict) -> dict:
"""示例任务函数"""
await asyncio.sleep(0.5)
if data.get("fail"):
raise ValueError("模拟失败")
return {"id": task_id, "result": data["value"]}
def progress_handler(completed, total, result):
"""进度回调"""
print(f"进度: {completed}/{total}, 任务 {result.task_id}: {result.status}")
async def main():
# 配置日志
logging.basicConfig(level=logging.INFO)
manager = BatchTaskManager(max_concurrency=3)
# 准备任务列表
tasks = []
for i in range(10):
task_id = f"task_{i}"
task_func = example_task
args = (task_id, {"value": i * 10, "fail": i == 5}) # 第6个任务会失败
kwargs = {}
tasks.append((task_id, task_func, args, kwargs))
# 执行批量任务
results = await manager.process_batch(tasks, progress_handler)
# 统计结果
success = sum(1 for r in results if r.status == 'success')
failed = sum(1 for r in results if r.status == 'failed')
print(f"完成: {len(results)} 个任务, 成功: {success}, 失败: {failed}")
# asyncio.run(main())
极简方案:使用asyncio.Queue
import asyncio
import random
class SimpleTaskQueue:
async def worker(self, worker_id: int, queue: asyncio.Queue):
"""工作协程"""
while True:
task = await queue.get()
if task is None: # 结束信号
break
task_id, func, args = task
print(f"Worker {worker_id} 处理任务 {task_id}")
try:
result = await func(*args)
print(f"Worker {worker_id} 完成任务 {task_id}: {result}")
except Exception as e:
print(f"Worker {worker_id} 任务 {task_id} 失败: {e}")
finally:
queue.task_done()
async def run(self, tasks: list, num_workers: int = 3):
"""运行任务队列"""
queue = asyncio.Queue()
# 添加任务
for task in tasks:
await queue.put(task)
# 添加结束信号
for _ in range(num_workers):
await queue.put(None)
# 创建工作协程
workers = [
asyncio.create_task(self.worker(i, queue))
for i in range(num_workers)
]
# 等待所有任务完成
await queue.join()
# 取消工作协程
for w in workers:
w.cancel()
print("所有任务完成")
# 使用示例
async def simple_task(data: str) -> str:
await asyncio.sleep(random.uniform(0.1, 0.5))
return f"处理结果: {data}"
async def main():
queue_runner = SimpleTaskQueue()
tasks = [
(i, simple_task, (f"数据{i}",))
for i in range(10)
]
await queue_runner.run(tasks, num_workers=3)
# asyncio.run(main())
- asyncio.gather: 最简单的方式,同时执行所有任务
- 信号量控制: Semaphore限制并发数
- TaskGroup (Python 3.11+): 结构化管理异常
- 任务队列: 适用于动态任务分配
- as_completed: 按完成顺序处理结果
- 重试机制: 提高任务执行成功率
选择哪种方案取决于:
- 任务数量
- 是否有并发限制
- 是否需要重试
- 是否需要进度回调
- Python版本要求
版权声明: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直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播