# EfficientWordCloud 并行优化设计文稿 ## 1. 目标与背景 本设计针对 EfficientWordCloud 的两个性能瓶颈进行优化: - **Python 侧**:文本渲染与 bbox 计算属于 CPU 密集型,原流程在主循环中串行执行。 - **C++ 侧**:可用位置搜索为线性扫描,且非线程安全,限制多核利用。 目标: - 在 Python 侧引入并行 bbox 预取,降低主循环阻塞。 - 在 C++ 侧实现线程安全与分块并行搜索,提升多核性能。 ## 2. 总体架构 ### 2.1 并行策略 - **Python 侧**:Producer-Consumer 预取模式。 - 使用 `ProcessPoolExecutor` 异步计算未来词语的 bbox。 - 主循环消费预取结果;若字体缩小,则回退为同步计算。 - **C++ 侧**:Chunked Parallel Search。 - 将候选坐标分块,每块由一个异步任务扫描。 - 收集所有任务结果,选择最小索引对应的位置,以保持“中心优先”的排序策略。 ### 2.2 线程安全模型 - `IntegralGrid` 内部引入 `std::shared_mutex`。 - **读**(`get_area_sum`)在并行搜索期间不再加锁,假设搜索阶段只读且在生成坐标与积分图后保持快照。 - **写**(`update_rect_add`)当前实现默认由单线程 Python 调用,移除了锁以减少开销;如需多线程更新需恢复写锁保护。 - 重建积分图(`rebuild_integral`)只在写路径触发。 ## 3. C++ 核心设计 ### 3.1 数据结构扩展 - 在 `IntegralGrid` 内部新增: ```cpp mutable std::shared_mutex mutex_; ``` ### 3.2 并行搜索流程 1. 计算线程数(`hardware_concurrency`),确定分块大小。 2. 对 `valid_coords` 分块后并行扫描,每块返回一个 `SearchResult`。 3. 主线程汇总所有结果,选取最小索引(全局最佳位置)。 4. 在搜索期间释放 GIL: ```cpp Py_BEGIN_ALLOW_THREADS ... Py_END_ALLOW_THREADS ``` ### 3.3 关键函数 - `search_range(start, end, box_h, box_w, step)`:扫描单块坐标。 - `find_spot_parallel(box_h, box_w, step)`:组织并行任务并聚合结果。 - `Grid_query_sorted`:绑定层调用 `find_spot_parallel`。 ## 4. Python 侧设计 ### 4.1 可序列化的测量函数 模块级函数保证可被 `ProcessPoolExecutor` 调度: ```python def measure_text(text, font_path, size, rotate) -> (int, int) ``` ### 4.2 ParallelBBoxFetcher 职责: - 维护任务队列。 - 提交预取任务。 - 主循环中拉取结果(若无缓存则同步测量)。 接口: - `prefetch(items)` - `get(key, text, size, rotate)` ### 4.3 主流程集成 - 预先生成 `rotation_flags`,确保预取与实际一致。 - 预取前 `N` 个词的 bbox。 - 逐词处理时,提前预取下一批的 bbox。 - 字体缩小后回退同步,保证正确性。 ## 5. 构建配置 - 编译标准升级为 C++17 以使用 `std::shared_mutex`。 ## 6. 影响与兼容性 - 对外 API 保持不变。 - 性能提升取决于多核环境及词数量。 - 并行搜索仍保证排序一致性。 ## 7. 风险与对策 - **多进程 bbox 测量开销**:采用预取窗口控制并发规模。 - **锁开销**:只在必要时加锁,读操作使用共享锁。 - **一致性**:聚合结果按最小索引保证行为与原排序一致。