feat: monitor→GUI日志回调,EasyOCR子进程初始化状态可在GUI日志中查看
- MessageMonitor 新增 _log_callback / set_log_callback / _gui_log
- _delayed_easyocr_start 启动时输出「🔧 EasyOCR 子进程初始化中...」
- _handshake_easyocr_subprocess 成功/超时/失败时输出对应状态
- _start_easyocr_proc_locked 启动失败时输出错误
- start() 中 _HAS_EASYOCR=False 或 broken 时输出警告
- gui.py 在 _log_queue 创建后调用 monitor.set_log_callback(self._log)
This commit is contained in:
@@ -54,14 +54,17 @@ def _force_system_memory_cleanup():
|
||||
logger.debug(f"SetProcessWorkingSetSize 失败: {e}")
|
||||
|
||||
# Python GC + torch CUDA 清理
|
||||
# ⭐ Task #1630: 修复内存687M——不主动 import torch(EasyOCR 已子进程化)
|
||||
# import torch 会加载 ~300MB DLL;主进程无 CUDA 状态,仅在 torch 已加载时才清理
|
||||
try:
|
||||
import torch
|
||||
if torch.cuda.is_available():
|
||||
torch.cuda.empty_cache()
|
||||
torch.cuda.synchronize()
|
||||
logger.debug("系统内存清理: torch.cuda.empty_cache 完成")
|
||||
except ImportError:
|
||||
pass # torch 未安装
|
||||
import sys as _sys
|
||||
if 'torch' in _sys.modules:
|
||||
_torch = _sys.modules['torch']
|
||||
if _torch.cuda.is_available():
|
||||
_torch.cuda.empty_cache()
|
||||
_torch.cuda.synchronize()
|
||||
logger.debug("系统内存清理: torch.cuda.empty_cache 完成")
|
||||
# else: torch 未加载,跳过
|
||||
except Exception as e:
|
||||
logger.debug(f"torch.cuda.empty_cache 失败: {e}")
|
||||
|
||||
@@ -221,7 +224,13 @@ class OCREngineManager:
|
||||
return False
|
||||
|
||||
def initialize(self):
|
||||
"""预初始化两套OCR引擎(EasyOCR GPU/CPU根据内存自动选择)"""
|
||||
"""预初始化OCR引擎(仅 Windows OCR)。
|
||||
|
||||
⭐ Task #1630: 修复内存687M——不在主进程中 import easyocr/torch!
|
||||
EasyOCR 已完全子进程化(easyocr_worker.py),主进程 import easyocr 会连带
|
||||
加载 torch DLL (~300MB),且 Python 无法卸载已加载的 DLL,导致内存永远不释放。
|
||||
主进程仅使用 Windows OCR;EasyOCR 通过 monitor.py 的子进程隔离方案使用。
|
||||
"""
|
||||
if self._initialized:
|
||||
return True
|
||||
|
||||
@@ -231,38 +240,8 @@ class OCREngineManager:
|
||||
|
||||
self._log("🔧 初始化OCR引擎...")
|
||||
|
||||
# 初始化EasyOCR(根据内存条件选择GPU/CPU)
|
||||
# ⭐ Task #1601: GPU 探针已拦截 CUDA 异常,此处用 try/except 兜底
|
||||
# access violation (native crash) 无法被 Python 捕获,
|
||||
# 但探针通过后此概率极低;CPU 模式不受 native crash 影响。
|
||||
use_gpu = False
|
||||
try:
|
||||
import easyocr
|
||||
use_gpu = self._check_memory_for_gpu()
|
||||
mode_str = "GPU" if use_gpu else "CPU"
|
||||
self._log(f" ⏳ 初始化EasyOCR ({mode_str}模式)...")
|
||||
try:
|
||||
self._easyocr_reader = easyocr.Reader(['ch_sim', 'en'], gpu=use_gpu, verbose=False)
|
||||
self._log(f" ✅ EasyOCR就绪({mode_str}模式)")
|
||||
except Exception as e:
|
||||
# GPU失败 → 降级CPU重试(注意:access violation 不可被 except 捕获)
|
||||
if use_gpu:
|
||||
self._log(f" ⚠ EasyOCR GPU初始化失败: {e},降级CPU重试...")
|
||||
try:
|
||||
self._easyocr_reader = easyocr.Reader(['ch_sim', 'en'], gpu=False, verbose=False)
|
||||
self._log(" ✅ EasyOCR就绪(CPU模式,GPU降级)")
|
||||
except Exception as e2:
|
||||
self._log(f" ⚠ EasyOCR CPU也失败: {e2}")
|
||||
self._easyocr_reader = None
|
||||
else:
|
||||
self._log(f" ⚠ EasyOCR初始化失败: {e}")
|
||||
self._easyocr_reader = None
|
||||
except ImportError:
|
||||
self._log(" ⚠ EasyOCR未安装")
|
||||
self._easyocr_reader = None
|
||||
except Exception as e:
|
||||
self._log(f" ⚠ EasyOCR异常: {e}")
|
||||
self._easyocr_reader = None
|
||||
# ⭐ EasyOCR 不再在主进程中初始化——子进程隔离方案已接管
|
||||
self._easyocr_reader = None
|
||||
|
||||
# 初始化Windows OCR
|
||||
try:
|
||||
@@ -277,12 +256,12 @@ class OCREngineManager:
|
||||
self._log(f" ⚠ Windows OCR初始化失败: {e}")
|
||||
self._winocr_engine = None
|
||||
|
||||
if not self._easyocr_reader and not self._winocr_engine:
|
||||
if not self._winocr_engine:
|
||||
self._log("❌ 无可用OCR引擎")
|
||||
return False
|
||||
|
||||
self._initialized = True
|
||||
self._use_gpu = use_gpu
|
||||
self._use_gpu = False
|
||||
self._last_use_time = time.time()
|
||||
self._start_timeout_timer()
|
||||
self._log("✅ OCR引擎初始化完成")
|
||||
@@ -602,6 +581,9 @@ class MsgBotApp(ctk.CTk):
|
||||
# 自动回复执行队列(转发到主线程,避免 daemon 线程 SetForegroundWindow 失败)
|
||||
self._reply_queue: queue.Queue[dict] = queue.Queue()
|
||||
|
||||
# ⭐ monitor→GUI 日志回调:EasyOCR 子进程初始化等关键状态转发到 GUI 日志
|
||||
self.monitor.set_log_callback(self._log)
|
||||
|
||||
# ⭐ 启动时系统内存清理(强制回收Python进程内存)
|
||||
self._log("🧹 启动内存清理...")
|
||||
threading.Thread(target=_force_system_memory_cleanup, daemon=True).start()
|
||||
|
||||
Reference in New Issue
Block a user