干掉 HistoryManager 内部两条 O(N) 全扫 hot path (Mac 仍闪退根因)
第二阶段发布后用户日志显示: 启动 8s 后 5s 内连续 5 次 load_history_index 全扫 513 条 + 513 次 stat, 主线程累计阻塞, 随后日志戛然而止 (典型 jetsam SIGKILL 指纹). 定位到两条阶段 1+2 没修的 hot path: 1. get_history_item(timestamp): 点击历史项查看详情时触发, 原走 load_history_index() + 线性查找. 改为直接调 load_history_item_fast() (读单个 metadata.json), O(1). 2. _update_history_index(history_item): 每次生成完图都调, 原走 load_history_index() 全扫 + from_dict + 路径修正 + 整表写回. 改为直接对 raw json list dict 操作, 无 stat / 无 from_dict. 改完之后 hot path 完全不再触发 _fix_history_path 循环.
Showing
1 changed file
with
31 additions
and
19 deletions
| ... | @@ -1006,19 +1006,14 @@ class HistoryManager: | ... | @@ -1006,19 +1006,14 @@ class HistoryManager: |
| 1006 | return [] | 1006 | return [] |
| 1007 | 1007 | ||
| 1008 | def get_history_item(self, timestamp: str) -> Optional[HistoryItem]: | 1008 | def get_history_item(self, timestamp: str) -> Optional[HistoryItem]: |
| 1009 | """获取指定时间戳的历史记录项 | 1009 | """获取指定时间戳的历史记录项。 |
| 1010 | 1010 | ||
| 1011 | Args: | 1011 | 以前实现走 load_history_index() 全扫 + 路径修正,每次 O(N) + N 次 stat。 |
| 1012 | timestamp: 时间戳 | 1012 | 在 Mac 用户 513 条历史的环境下,点击历史项查看详情会触发主线程 |
| 1013 | 1013 | 阻塞 ~60ms; 连续点击会累积内存峰值并触发 jetsam SIGKILL。 | |
| 1014 | Returns: | 1014 | 现改为直接读 {timestamp}/metadata.json + 同目录扫描,O(1)。 |
| 1015 | 历史记录项,如果不存在则返回None | ||
| 1016 | """ | 1015 | """ |
| 1017 | history_items = self.load_history_index() | 1016 | return self.load_history_item_fast(timestamp) |
| 1018 | for item in history_items: | ||
| 1019 | if item.timestamp == timestamp: | ||
| 1020 | return item | ||
| 1021 | return None | ||
| 1022 | 1017 | ||
| 1023 | def load_history_item_fast(self, timestamp: str) -> Optional[HistoryItem]: | 1018 | def load_history_item_fast(self, timestamp: str) -> Optional[HistoryItem]: |
| 1024 | """轻量读取单条历史记录:直接从 {timestamp}/metadata.json + 文件扫描。 | 1019 | """轻量读取单条历史记录:直接从 {timestamp}/metadata.json + 文件扫描。 |
| ... | @@ -1082,18 +1077,35 @@ class HistoryManager: | ... | @@ -1082,18 +1077,35 @@ class HistoryManager: |
| 1082 | return False | 1077 | return False |
| 1083 | 1078 | ||
| 1084 | def _update_history_index(self, history_item: HistoryItem): | 1079 | def _update_history_index(self, history_item: HistoryItem): |
| 1085 | """更新历史记录索引 | 1080 | """更新历史记录索引(每次生成完图片都会调用,hot path)。 |
| 1086 | 1081 | ||
| 1087 | Args: | 1082 | 老实现走 load_history_index() 全扫 + 路径修正 + N 次 stat,再 |
| 1088 | history_item: 要添加的历史记录项 | 1083 | 整个 list 反序列化 + 重新写回。513 条历史时主线程阻塞 ~60ms, |
| 1084 | Mac 上累计触发 jetsam SIGKILL。 | ||
| 1085 | 现改为直接对 raw json 列表 dict 操作:读->过滤->插首位->写。 | ||
| 1086 | 无 stat、无 from_dict、无路径修正。 | ||
| 1089 | """ | 1087 | """ |
| 1090 | history_items = self.load_history_index() | 1088 | try: |
| 1089 | if self.history_index_file.exists(): | ||
| 1090 | with open(self.history_index_file, 'r', encoding='utf-8') as f: | ||
| 1091 | raw = json.load(f) | ||
| 1092 | if not isinstance(raw, list): | ||
| 1093 | raw = [] | ||
| 1094 | else: | ||
| 1095 | raw = [] | ||
| 1096 | except Exception as e: | ||
| 1097 | self.logger.error(f"_update_history_index 读取索引失败: {e}") | ||
| 1098 | raw = [] | ||
| 1091 | 1099 | ||
| 1092 | # 检查是否已存在相同时间戳的记录,如果存在则替换 | 1100 | new_ts = history_item.timestamp |
| 1093 | history_items = [item for item in history_items if item.timestamp != history_item.timestamp] | 1101 | raw = [d for d in raw if isinstance(d, dict) and d.get('timestamp') != new_ts] |
| 1094 | history_items.insert(0, history_item) # 插入到开头 | 1102 | raw.insert(0, history_item.to_dict()) |
| 1095 | 1103 | ||
| 1096 | self._save_history_index(history_items) | 1104 | try: |
| 1105 | with open(self.history_index_file, 'w', encoding='utf-8') as f: | ||
| 1106 | json.dump(raw, f, ensure_ascii=False, indent=2) | ||
| 1107 | except Exception as e: | ||
| 1108 | self.logger.error(f"_update_history_index 写入索引失败: {e}") | ||
| 1097 | 1109 | ||
| 1098 | def _save_history_index(self, history_items: List[HistoryItem]): | 1110 | def _save_history_index(self, history_items: List[HistoryItem]): |
| 1099 | """保存历史记录索引到文件 | 1111 | """保存历史记录索引到文件 | ... | ... |
-
Please register or sign in to post a comment