fish_async_task.performance.resource_manager 源代码

"""
任务资源管理模块

提供任务资源跟踪和清理功能,防止资源泄漏。
"""

import logging
import threading
import time
from collections import deque
from typing import Any, Callable, Dict, List, Optional, Set


class TaskResource:
    """任务资源封装"""

    def __init__(
        self,
        resource_id: str,
        resource: Any,
        cleanup_func: Optional[Callable[[], None]] = None,
    ):
        """
        初始化任务资源

        Args:
            resource_id: 资源唯一标识
            resource: 资源对象
            cleanup_func: 资源清理函数(可选)
        """
        self.resource_id = resource_id
        self.resource = resource
        self.cleanup_func = cleanup_func
        self.created_at = time.time()
        self.last_used = time.time()

    def update_last_used(self) -> None:
        """更新最后使用时间"""
        self.last_used = time.time()

    def cleanup(self) -> bool:
        """
        清理资源

        Returns:
            bool: 清理是否成功
        """
        if self.cleanup_func:
            try:
                self.cleanup_func()
                return True
            except Exception as e:
                logging.warning(f"资源清理函数执行失败 [{self.resource_id}]: {e}")
                return False
        return False


[文档] class TaskResourceManager: """任务资源管理器 - 跟踪和管理任务相关资源""" MAX_TRACKED_RESOURCES = 10000 DEFAULT_CLEANUP_TIMEOUT = 2.0
[文档] def __init__( self, logger: logging.Logger = None, max_tracked: int = MAX_TRACKED_RESOURCES, ): """ 初始化任务资源管理器 Args: logger: 日志记录器 max_tracked: 最大跟踪资源数 """ self.logger = logger or logging.getLogger(__name__) self._max_tracked = max_tracked self._resources: Dict[str, TaskResource] = {} self._task_resources: Dict[str, Set[str]] = {} self._lock = threading.Lock() self._cleanup_queue: deque = deque(maxlen=1000) self._cleanup_thread: Optional[threading.Thread] = None self._running = threading.Event()
[文档] def start(self) -> None: """启动资源清理线程""" if self._running.is_set(): return self._running.set() self._cleanup_thread = threading.Thread( target=self._cleanup_loop, name="TaskResourceCleanup", daemon=True, ) self._cleanup_thread.start() self.logger.debug("任务资源清理线程已启动")
[文档] def stop(self, timeout: float = DEFAULT_CLEANUP_TIMEOUT) -> None: """ 停止资源清理线程 Args: timeout: 等待超时时间(秒) """ if not self._running.is_set(): return self._running.clear() if self._cleanup_thread and self._cleanup_thread.is_alive(): self._cleanup_thread.join(timeout=timeout) if self._cleanup_thread.is_alive(): self.logger.warning("资源清理线程在超时后仍未退出")
[文档] def register_resource( self, task_id: str, resource_id: str, resource: Any, cleanup_func: Optional[Callable[[], None]] = None, ) -> None: """ 注册任务资源 Args: task_id: 任务ID resource_id: 资源唯一标识 resource: 资源对象 cleanup_func: 资源清理函数(可选) """ with self._lock: task_resource = TaskResource(resource_id, resource, cleanup_func) if len(self._resources) >= self._max_tracked: self._evict_oldest_resources(count=100) self._resources[resource_id] = task_resource if task_id not in self._task_resources: self._task_resources[task_id] = set() self._task_resources[task_id].add(resource_id)
[文档] def unregister_resource(self, resource_id: str) -> bool: """ 注销资源 Args: resource_id: 资源唯一标识 Returns: bool: 是否成功注销 """ with self._lock: if resource_id not in self._resources: return False resource = self._resources[resource_id] resource.cleanup() for task_id, resources in self._task_resources.items(): resources.discard(resource_id) del self._resources[resource_id] return True
[文档] def register_task(self, task_id: str) -> None: """ 注册任务(用于跟踪) Args: task_id: 任务ID """ with self._lock: if task_id not in self._task_resources: self._task_resources[task_id] = set()
[文档] def cleanup_task_resources(self, task_id: str, timeout: float = DEFAULT_CLEANUP_TIMEOUT) -> int: """ 清理任务的所有资源 Args: task_id: 任务ID timeout: 等待超时时间(秒) Returns: int: 清理的资源数量 """ with self._lock: if task_id not in self._task_resources: return 0 resource_ids = self._task_resources[task_id] cleaned_count = 0 for resource_id in list(resource_ids): if resource_id in self._resources: resource = self._resources[resource_id] if timeout > 0: cleanup_thread = threading.Thread( target=resource.cleanup, daemon=True, ) cleanup_thread.start() cleanup_thread.join(timeout=timeout) else: resource.cleanup() del self._resources[resource_id] cleaned_count += 1 del self._task_resources[task_id] return cleaned_count
[文档] def force_cleanup_task(self, task_id: str) -> int: """ 强制清理任务资源(不使用线程) Args: task_id: 任务ID Returns: int: 清理的资源数量 """ with self._lock: if task_id not in self._task_resources: return 0 resource_ids = self._task_resources[task_id] cleaned_count = 0 for resource_id in list(resource_ids): if resource_id in self._resources: try: self._resources[resource_id].cleanup() except Exception as e: self.logger.warning(f"资源清理失败 [{resource_id}]: {e}") del self._resources[resource_id] cleaned_count += 1 del self._task_resources[task_id] return cleaned_count
def _evict_oldest_resources(self, count: int = 100) -> None: """驱逐最旧的资源""" if not self._resources: return sorted_resources = sorted( self._resources.items(), key=lambda x: x[1].last_used, ) evicted = 0 for resource_id, resource in sorted_resources: if evicted >= count: break resource.cleanup() del self._resources[resource_id] evicted += 1 for task_id, resources in self._task_resources.items(): resources.discard(resource_id) if evicted > 0: self.logger.debug(f"驱逐了 {evicted} 个过期资源") def _cleanup_loop(self) -> None: """资源清理循环""" while self._running.is_set(): try: self._perform_cleanup() time.sleep(1.0) except Exception as e: self.logger.error(f"资源清理循环异常: {e}") def _perform_cleanup(self) -> int: """ 执行资源清理 Returns: int: 清理的资源数量 """ cleaned_count = 0 now = time.time() with self._lock: expired_resources = [ (rid, r) for rid, r in self._resources.items() if now - r.last_used > 3600 ] for resource_id, resource in expired_resources[:100]: try: resource.cleanup() except Exception as e: self.logger.warning(f"资源清理失败 [{resource_id}]: {e}") del self._resources[resource_id] cleaned_count += 1 for task_id in self._task_resources: self._task_resources[task_id].discard(resource_id) return cleaned_count
[文档] def get_resource_count(self) -> int: """ 获取当前跟踪的资源数量 Returns: int: 资源数量 """ with self._lock: return len(self._resources)
[文档] def get_task_resource_count(self, task_id: str) -> int: """ 获取任务的资源数量 Args: task_id: 任务ID Returns: int: 资源数量 """ with self._lock: if task_id not in self._task_resources: return 0 return len(self._task_resources[task_id])
[文档] def get_stats(self) -> Dict[str, Any]: """ 获取资源管理统计信息 Returns: Dict[str, Any]: 统计信息 """ with self._lock: return { "total_resources": len(self._resources), "tracked_tasks": len(self._task_resources), "max_tracked": self._max_tracked, "cleanup_queue_size": len(self._cleanup_queue), }
[文档] class TimeoutTaskTracker: """超时任务跟踪器 - 跟踪并管理超时任务""" DEFAULT_TASK_EXPIRY = 3600
[文档] def __init__( self, logger: logging.Logger = None, max_tracked: int = 1000, task_expiry: int = DEFAULT_TASK_EXPIRY, ): """ 初始化超时任务跟踪器 Args: logger: 日志记录器 max_tracked: 最大跟踪任务数 task_expiry: 任务信息过期时间(秒) """ self.logger = logger or logging.getLogger(__name__) self._max_tracked = max_tracked self._task_expiry = task_expiry self._timed_out_tasks: Dict[str, Dict[str, Any]] = {} self._lock = threading.Lock()
[文档] def track_timeout_task( self, task_id: str, thread: threading.Thread, submit_time: float = None, ) -> None: """ 跟踪超时任务 Args: task_id: 任务ID thread: 任务执行线程 submit_time: 任务提交时间 """ with self._lock: if len(self._timed_out_tasks) >= self._max_tracked: self._cleanup_expired() self._timed_out_tasks[task_id] = { "thread": thread, "submit_time": submit_time or time.time(), "timeout_time": time.time(), } self.logger.debug(f"跟踪超时任务: {task_id}")
[文档] def untrack_task(self, task_id: str) -> bool: """ 取消跟踪任务 Args: task_id: 任务ID Returns: bool: 是否成功取消跟踪 """ with self._lock: if task_id in self._timed_out_tasks: del self._timed_out_tasks[task_id] return True return False
def _cleanup_expired(self) -> int: """清理过期任务记录""" now = time.time() expired = [ tid for tid, info in self._timed_out_tasks.items() if now - info["timeout_time"] > self._task_expiry ] for tid in expired: del self._timed_out_tasks[tid] return len(expired)
[文档] def get_tracked_count(self) -> int: """ 获取跟踪的任务数量 Returns: int: 任务数量 """ with self._lock: return len(self._timed_out_tasks)
[文档] def get_stats(self) -> Dict[str, Any]: """ 获取跟踪器统计信息 Returns: Dict[str, Any]: 统计信息 """ with self._lock: return { "tracked_tasks": len(self._timed_out_tasks), "max_tracked": self._max_tracked, "task_expiry_seconds": self._task_expiry, }