|
@@ -799,6 +799,29 @@ _WIN_CACHE: dict = {'sysmx': {}, 'curves': {}}
|
|
|
_WIN_BUSY: dict = {'sysmx': set(), 'curves': set()}
|
|
_WIN_BUSY: dict = {'sysmx': set(), 'curves': set()}
|
|
|
_WIN_ERR: dict = {'sysmx': {}, 'curves': {}}
|
|
_WIN_ERR: dict = {'sysmx': {}, 'curves': {}}
|
|
|
_WIN_LOCK = _thr.Lock()
|
|
_WIN_LOCK = _thr.Lock()
|
|
|
|
|
+# ★重活**串行**(2026-09-21 服务器实逮): 预热与请求各自起线程 ⇒ 同时跑两个按窗重算(各几百 MB 级
|
|
|
|
|
+# 中间帧),小内存机器上进程被系统杀掉(日志停在"按窗重算启动"两行、随后网关 503)。
|
|
|
|
|
+# 现在全部重活排队执行:峰值 = 1 份中间帧。
|
|
|
|
|
+_HEAVY_LOCK = _thr.Lock()
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+def _mem_mb():
|
|
|
|
|
+ """本进程可用内存(MB);拿不到就返回 None(不因为这些诊断信息把重算搞挂)。"""
|
|
|
|
|
+ try:
|
|
|
|
|
+ import ctypes
|
|
|
|
|
+
|
|
|
|
|
+ class _MS(ctypes.Structure):
|
|
|
|
|
+ _fields_ = [('dwLength', ctypes.c_ulong), ('dwMemoryLoad', ctypes.c_ulong),
|
|
|
|
|
+ ('ullTotalPhys', ctypes.c_ulonglong), ('ullAvailPhys', ctypes.c_ulonglong),
|
|
|
|
|
+ ('ullTotalPageFile', ctypes.c_ulonglong), ('ullAvailPageFile', ctypes.c_ulonglong),
|
|
|
|
|
+ ('ullTotalVirtual', ctypes.c_ulonglong), ('ullAvailVirtual', ctypes.c_ulonglong),
|
|
|
|
|
+ ('ullAvailExtendedVirtual', ctypes.c_ulonglong)]
|
|
|
|
|
+ st = _MS()
|
|
|
|
|
+ st.dwLength = ctypes.sizeof(_MS)
|
|
|
|
|
+ ctypes.windll.kernel32.GlobalMemoryStatusEx(ctypes.byref(st))
|
|
|
|
|
+ return int(st.ullAvailPhys // (1024 * 1024))
|
|
|
|
|
+ except Exception:
|
|
|
|
|
+ return None
|
|
|
|
|
|
|
|
|
|
|
|
|
def _win_key(win):
|
|
def _win_key(win):
|
|
@@ -817,7 +840,11 @@ def _win_get(kind, win, fn):
|
|
|
|
|
|
|
|
def _run():
|
|
def _run():
|
|
|
try:
|
|
try:
|
|
|
- v = fn()
|
|
|
|
|
|
|
+ with _HEAVY_LOCK: # 重活串行: 同一时刻只算一份
|
|
|
|
|
+ m0 = _mem_mb()
|
|
|
|
|
+ print(f'[win] {kind} 按窗重算开算 {key}(可用内存 {m0} MB)', flush=True)
|
|
|
|
|
+ v = fn()
|
|
|
|
|
+ print(f'[win] {kind} 按窗重算完成 {key}(可用内存 {_mem_mb()} MB)', flush=True)
|
|
|
except Exception as e: # 守护失败必响亮
|
|
except Exception as e: # 守护失败必响亮
|
|
|
_WIN_ERR[kind][key] = f'{type(e).__name__}: {e}'[:200]
|
|
_WIN_ERR[kind][key] = f'{type(e).__name__}: {e}'[:200]
|
|
|
print(f'[win] {kind} 按窗重算失败 {key}: {_WIN_ERR[kind][key]}', flush=True)
|
|
print(f'[win] {kind} 按窗重算失败 {key}: {_WIN_ERR[kind][key]}', flush=True)
|
|
@@ -5431,12 +5458,17 @@ if __name__ == '__main__':
|
|
|
# 判级矩阵 ≈25 s/窗、镜头 ≈10~45 s/窗 —— 不预热的话重启后第一个访客要等 pending 轮询。
|
|
# 判级矩阵 ≈25 s/窗、镜头 ≈10~45 s/窗 —— 不预热的话重启后第一个访客要等 pending 轮询。
|
|
|
# 这里在**后台守护线程**里顺序把预设窗算进进程缓存(页面照常可用,未就位的窗如实标 pending)。
|
|
# 这里在**后台守护线程**里顺序把预设窗算进进程缓存(页面照常可用,未就位的窗如实标 pending)。
|
|
|
def _warm():
|
|
def _warm():
|
|
|
|
|
+ if _os.environ.get('GUANLAN_WIN_WARM', '1') == '0':
|
|
|
|
|
+ print('[warm] 按窗预热被 GUANLAN_WIN_WARM=0 关掉(按需算,首次看窗会 pending 一轮)', flush=True)
|
|
|
|
|
+ return
|
|
|
|
|
+ import time as _t
|
|
|
n = 0
|
|
n = 0
|
|
|
for w in list(WINDOWS):
|
|
for w in list(WINDOWS):
|
|
|
try:
|
|
try:
|
|
|
sysmx_of(w) # 未命中即起后台线程
|
|
sysmx_of(w) # 未命中即起后台线程
|
|
|
if _win_wait('sysmx', w, timeout=180) is not None:
|
|
if _win_wait('sysmx', w, timeout=180) is not None:
|
|
|
n += 1
|
|
n += 1
|
|
|
|
|
+ _t.sleep(2) # 留口气: 小内存机器上连续重算更容易被系统盯上
|
|
|
except Exception as e:
|
|
except Exception as e:
|
|
|
print(f'[warm] 判级 {w} 失败: {type(e).__name__}: {e}'[:160], flush=True)
|
|
print(f'[warm] 判级 {w} 失败: {type(e).__name__}: {e}'[:160], flush=True)
|
|
|
for w in ('2026年',):
|
|
for w in ('2026年',):
|
|
@@ -5445,7 +5477,7 @@ if __name__ == '__main__':
|
|
|
_win_wait('curves', w, timeout=240)
|
|
_win_wait('curves', w, timeout=240)
|
|
|
except Exception as e:
|
|
except Exception as e:
|
|
|
print(f'[warm] 镜头 {w} 失败: {type(e).__name__}: {e}'[:160], flush=True)
|
|
print(f'[warm] 镜头 {w} 失败: {type(e).__name__}: {e}'[:160], flush=True)
|
|
|
- print(f'[warm] 按窗缓存预热完成: 判级 {n}/{len(WINDOWS)} 窗', flush=True)
|
|
|
|
|
|
|
+ print(f'[warm] 按窗缓存预热完成: 判级 {n}/{len(WINDOWS)} 窗(可用内存 {_mem_mb()} MB)', flush=True)
|
|
|
|
|
|
|
|
_thr.Thread(target=_warm, name='win-warm', daemon=True).start()
|
|
_thr.Thread(target=_warm, name='win-warm', daemon=True).start()
|
|
|
ThreadingHTTPServer((_host, a.port), H).serve_forever()
|
|
ThreadingHTTPServer((_host, a.port), H).serve_forever()
|