fish_async_task.worker.adaptive 源代码
"""
自适应线程管理模块
包含自适应工作线程管理器和 CPU 监控器。
"""
import logging
import time
from collections import deque
from typing import Any, Deque, Dict, List, Optional
[文档]
class CPUMonitor:
"""
CPU使用率监控器
使用psutil获取系统CPU使用率,支持采样平均。
"""
[文档]
def __init__(self, sample_interval: float = 0.5, sample_count: int = 3):
"""
初始化CPU监控器
Args:
sample_interval: 每次采样的时间间隔(秒)
sample_count: 采样次数,用于计算平均CPU使用率
"""
self.sample_interval = sample_interval
self.sample_count = sample_count
self._psutil_available = self._check_psutil()
def _check_psutil(self) -> bool:
"""
检查psutil是否可用
Returns:
bool: 如果psutil可用则返回True
"""
try:
import psutil # noqa: F401
return True
except ImportError:
return False
[文档]
def get_cpu_usage(self) -> Optional[float]:
"""
获取CPU使用率
如果psutil不可用,返回None。
Returns:
float: CPU使用率(0.0-1.0),如果不可用则返回None
"""
if not self._psutil_available:
return None
try:
import psutil
# 采样多次计算平均CPU使用率
cpu_percentages: List[float] = []
for _ in range(self.sample_count):
cpu_percent = psutil.cpu_percent(interval=self.sample_interval)
cpu_percentages.append(float(cpu_percent))
# 返回平均CPU使用率
avg_cpu = sum(cpu_percentages) / len(cpu_percentages)
return avg_cpu / 100.0 # 转换为0.0-1.0范围
except Exception:
# 如果获取失败,返回None
return None
[文档]
def get_cpu_count(self) -> int:
"""
获取CPU核心数
如果psutil不可用或返回None,返回1。
Returns:
int: CPU核心数
"""
if not self._psutil_available:
return 1
try:
import psutil
count = psutil.cpu_count()
return count if count is not None else 1
except Exception:
return 1
[文档]
class AdaptiveWorkerManager:
"""
自适应工作线程管理器
基于CPU使用率、队列积压和任务执行时间动态调整线程数量。
支持CPU监控,在CPU使用率过高时避免过度扩容。
使用场景:
- 任务负载波动较大的场景
- 需要根据系统负载自动调整资源的场景
- CPU密集型和I/O密集型任务混合的场景
配置说明:
- min_workers / max_workers: 线程数边界
- cpu_threshold: CPU使用率阈值,超过此值时避免扩容
- queue_threshold_high: 队列积压阈值,达到此值时触发扩容
- queue_threshold_low: 队列空闲阈值,低于此值时触发缩容
- scale_up_cooldown: 扩容冷却期(秒),避免频繁扩容
- scale_down_cooldown: 缩容冷却期(秒),避免频繁缩容
"""
[文档]
def __init__(
self,
min_workers: int,
max_workers: int,
cpu_threshold: float = 0.8,
queue_threshold_high: int = 100,
queue_threshold_low: int = 10,
scale_up_cooldown: float = 5.0,
scale_down_cooldown: float = 30.0,
use_cpu_monitoring: bool = True,
):
"""
初始化自适应工作线程管理器
Args:
min_workers: 最小工作线程数
max_workers: 最大工作线程数
cpu_threshold: CPU使用率阈值(0.0-1.0),超过此值时避免扩容
queue_threshold_high: 队列积压高阈值,达到此值时触发扩容
queue_threshold_low: 队列空闲低阈值,低于此值且空闲超时后触发缩容
scale_up_cooldown: 扩容冷却期(秒)
scale_down_cooldown: 缩容冷却期(秒)
use_cpu_monitoring: 是否启用CPU监控
"""
self.min_workers = min_workers
self.max_workers = max_workers
self.cpu_threshold = cpu_threshold
self.queue_threshold_high = queue_threshold_high
self.queue_threshold_low = queue_threshold_low
self.scale_up_cooldown = scale_up_cooldown
self.scale_down_cooldown = scale_down_cooldown
self.use_cpu_monitoring = use_cpu_monitoring
# 冷却期跟踪
self._last_scale_up = 0.0
self._last_scale_down = 0.0
# 任务执行时间统计(最近100个任务)
self._task_times: Deque[float] = deque(maxlen=100)
# CPU监控器(可选)
self._cpu_monitor: Optional["CPUMonitor"] = None
if use_cpu_monitoring:
self._cpu_monitor = CPUMonitor()
[文档]
def should_scale_up(
self,
current_workers: int,
queue_size: int,
cpu_usage: Optional[float] = None,
) -> bool:
"""
判断是否应该扩展线程
扩容条件(需全部满足):
1. 当前线程数小于最大限制
2. 距离上次扩容超过冷却期
3. 队列积压超过高阈值 或 CPU使用率低于阈值
Args:
current_workers: 当前工作线程数
queue_size: 当前队列积压任务数
cpu_usage: 当前CPU使用率(0.0-1.0),可选
Returns:
bool: 如果应该扩容则返回True
"""
now = time.time()
# 条件1: 检查最大线程数限制
if current_workers >= self.max_workers:
return False
# 条件2: 检查扩容冷却期
if now - self._last_scale_up < self.scale_up_cooldown:
return False
# 条件3: 队列积压检查
if queue_size > self.queue_threshold_high:
self._last_scale_up = now
return True
# 条件4: CPU使用率检查(如果启用)
if self.use_cpu_monitoring and cpu_usage is not None:
if cpu_usage < self.cpu_threshold and queue_size > current_workers:
self._last_scale_up = now
return True
return False
[文档]
def should_scale_down(
self,
current_workers: int,
queue_size: int,
idle_time: Optional[float] = None,
) -> bool:
"""
判断是否应该缩减线程
缩容条件(需全部满足):
1. 当前线程数大于最小限制
2. 距离上次缩容超过冷却期
3. 队列为空且空闲时间超过阈值
Args:
current_workers: 当前工作线程数
queue_size: 当前队列积压任务数
idle_time: 队列空闲时间(秒),可选
Returns:
bool: 如果应该缩容则返回True
"""
now = time.time()
# 条件1: 检查最小线程数限制
if current_workers <= self.min_workers:
return False
# 条件2: 检查缩容冷却期
if now - self._last_scale_down < self.scale_down_cooldown:
return False
# 条件3: 队列为空且空闲时间超过缩容冷却期
if queue_size == 0 and idle_time is not None:
# 如果冷却期已禁用(scale_down_cooldown <= 0),不允许缩容
if self.scale_down_cooldown <= 0:
return False
# 如果空闲时间超过缩容冷却期,可以缩容
if idle_time >= self.scale_down_cooldown:
self._last_scale_down = now
return True
return False
[文档]
def record_task_time(self, task_time: float) -> None:
"""
记录任务执行时间
Args:
task_time: 任务执行时间(秒)
"""
self._task_times.append(task_time)
[文档]
def get_avg_task_time(self) -> float:
"""
获取平均任务执行时间
Returns:
float: 平均任务执行时间(秒),如果没有数据则返回0
"""
if not self._task_times:
return 0.0
return sum(self._task_times) / len(self._task_times)
[文档]
def get_cpu_usage(self) -> Optional[float]:
"""
获取当前CPU使用率
Returns:
float: CPU使用率(0.0-1.0),如果CPU监控不可用则返回None
"""
if self._cpu_monitor is not None:
return self._cpu_monitor.get_cpu_usage()
return None
[文档]
def get_stats(self) -> Dict[str, Any]:
"""
获取管理器统计信息
Returns:
Dict[str, Any]: 统计信息字典
"""
return {
"min_workers": self.min_workers,
"max_workers": self.max_workers,
"cpu_threshold": self.cpu_threshold,
"queue_threshold_high": self.queue_threshold_high,
"queue_threshold_low": self.queue_threshold_low,
"scale_up_cooldown": self.scale_up_cooldown,
"scale_down_cooldown": self.scale_down_cooldown,
"use_cpu_monitoring": self.use_cpu_monitoring,
"avg_task_time": self.get_avg_task_time(),
"task_count": len(self._task_times),
"cpu_usage": self.get_cpu_usage(),
"last_scale_up": self._last_scale_up,
"last_scale_down": self._last_scale_down,
}