Appearance
text
# Related Code
main.py - 入口点和初始化
src/unified_downloader.py - 核心下载架构
src/ui.py - UI 层架构概览
设计哲学
简单优于抽象:没有过度工程化的接口和工厂模式,用简单的配置字典驱动平台差异。
进程隔离:下载操作在独立进程中运行,UI 永不卡顿。
配置驱动:新增平台只需在 PLATFORM_CONFIGS 添加配置,无需修改核心逻辑。
系统上下文
分层架构
核心设计决策
1. 为什么用多进程而非多线程?
| 方案 | 问题 |
|---|---|
| 单线程 | 下载时 UI 冻结 |
| 多线程 | Python GIL 限制,huggingface_hub 内部状态不线程安全 |
| 多进程 | 完全隔离,SDK 内部状态互不影响 |
2. 为什么用 spawn 而非 fork?
python
# main.py:16
MULTIPROCESSING_START_METHOD = "spawn"| 方法 | macOS 行为 | PyInstaller 兼容性 |
|---|---|---|
| fork | 可能导致 crash(PyQt fork 不安全) | 差 |
| spawn | 安全启动新解释器 | 好 |
3. 平台抽象策略
没有使用接口/继承,而是用简单的配置字典:
python
# src/unified_downloader.py:20-38
PLATFORM_CONFIGS = {
"huggingface": {
"token_env": "HF_TOKEN",
"endpoint_env": "HF_ENDPOINT",
"logger_name": "huggingface_hub",
"default_endpoint": "https://huggingface.co",
...
},
"modelscope": {
"token_env": "MODELSCOPE_API_TOKEN",
...
},
}为什么不用抽象基类?
- 只有 2 个平台,过度抽象是浪费
- 配置字典更易读、更易扩展
- 避免 Python 动态特性滥用
数据流
线程安全设计
关键类:
SafePipeWriter:进程安全的管道写入ThreadSafeSignalEmitter:跨线程信号发射器,使用 QMutex 保护LoggerManager:单例模式管理日志处理器,防止内存泄漏
错误处理策略
| 错误类型 | 处理方式 |
|---|---|
| 网络错误 | SDK 内部重试,超时后报错 |
| 认证错误 | 直接抛出,UI 显示错误 |
| 取消操作 | 优雅终止进程,清理资源 |
| 进程 crash | 捕获并报告,不影响 UI |