Prhub

#26675 [mem_cache][1/N] refactor: split allocator.py into allocator/ subpackage

原始 PR 作者 alphabetc1 合并时间 2026-05-31 20:31 文件变更 4 提交数 1 评论 12 代码增减 +212 / -148

执行摘要

将 allocator.py 拆分为 allocator/ 子包

PR 是 Issue #25371(父 Issue #24335)「allocator-promotion」系列的第一部分。目标是将 allocator.py 拆分为 allocator/ 子包,每个文件对应一种分配策略,以遵循父 Issue 的设计规则,并为后续将 SWATokenToKVPoolAllocator、HiSparse 分配器和 Mamba 分配器迁入同一包做好准备。

该 PR 是模块拆分的最佳实践,适合关注代码组织和重构策略的开发者学习。它展示了如何在不破坏现有 API 的情况下逐步重构,并保留 Git 历史。推荐精读以了解子包拆分和向后兼容的导入模式。

讨论亮点

Review 中仅有一个讨论线程:ispobock 建议调整 base.pyfrom __future__ import annotations 与注释的顺序,作者已调整。无其他争议。

实现拆解

  1. 通过 git mvallocator.py 重命名为 allocator/paged.py,Git 自动检测为 R073 重命名,保留 PagedTokenToKVPoolAllocator 及其辅助函数的完整历史。

  2. 新建 allocator/base.py,将 BaseTokenToKVPoolAllocator 抽象基类从原文件搬入此处,仅调整导入(删除 triton 等不必要依赖,添加 from sglang.srt.mem_cache.allocator.base import BaseTokenToKVPoolAllocator)。

  3. 新建 allocator/token.py,将 TokenToKVPoolAllocator (page_size=1 的单页分配器)搬入,继承自 base.py 中基类。

  4. 新建 allocator/__init__.py,重新导出所有公共类和辅助函数,确保 from sglang.srt.mem_cache.allocator import X 的旧导入路径继续生效。同时更新 paged.py 的导入以引用 base.py

  5. 验证:运行相关单元测试(934 passed)和 gsm8k 精度/速度基准,结果与 base 一致,确认无行为变化。

文件 模块 状态 重要度
python/sglang/srt/mem_cache/allocator/paged.py 内存分配器 renamed 8.57
python/sglang/srt/mem_cache/allocator/base.py 内存分配器 added 8.16
python/sglang/srt/mem_cache/allocator/token.py 内存分配器 added 8.05
python/sglang/srt/mem_cache/allocator/__init__.py 内存分配器 added 5.5

关键符号

BaseTokenToKVPoolAllocator TokenToKVPoolAllocator PagedTokenToKVPoolAllocator alloc_extend_naive alloc_extend_kernel alloc_decode_kernel

关键源码片段

python/sglang/srt/mem_cache/allocator/paged.py rename-or-move

核心来源文件,通过 `git mv` 从原 `allocator.py` 重命名得来,保留了 `PagedTokenToKVPoolAllocator` 及其辅助函数的完整历史。

"""Page-aligned memory pool."""from __future__ import annotationsfrom typing import TYPE_CHECKINGimport torch
import triton
import triton.language as tl# 导入新的基类,而非在同文件中定义
from sglang.srt.mem_cache.allocator.base import BaseTokenToKVPoolAllocator
from sglang.srt.utils import get_bool_env_var, get_num_new_pages, next_power_of_2if TYPE_CHECKING:
    from sglang.srt.mem_cache.memory_pool import KVCache
​
​
# 以下辅助函数和类在原文件中原封不动保留
def alloc_extend_naive(prefix_lens, seq_lens, last_loc, free_pages, out_indices, page_size, device):
    """..."""
    # ... 实现略
​
​
class PagedTokenToKVPoolAllocator(BaseTokenToKVPoolAllocator):
    """Page-size >= 1 的分页分配器。"""
    # ... 实现略
python/sglang/srt/mem_cache/allocator/base.py dependency-wiring

新建立的抽象基类文件,定义了所有分配器的公共接口。

"""Token-to-KV-slot 分配器的抽象基类。"""from __future__ import annotationsimport abc
from typing import TYPE_CHECKINGimport torchif TYPE_CHECKING:
    from sglang.srt.mem_cache.memory_pool import KVCache
​
​
class BaseTokenToKVPoolAllocator(abc.ABC):
    @abc.abstractmethod
    def __init__(self, size: int, page_size: int, dtype: torch.dtype, device: str, kvcache: KVCache, need_sort: bool):
        self.size = size
        self.page_size = page_size
        # ... 省略其他属性
​
    @property
    def size_full(self):
        return self.size
​
    def available_size(self):
        return (len(self.free_pages) + len(self.release_pages)) * self.page_size
​
    # ... 其他方法

评论区精华

代码风格:import 与注释的顺序 style

ispobock 在 base.py 中评论:能否将 import 放在注释下方?alphabetc1 回复已调整,并解释这样更常见。

结论:已调整 import 顺序,将 `from __future__ import annotations` 放在模块文档字符串之后。 · 已解决

风险与影响

变更风险低,因为这是纯机械代码搬迁,类体完全未修改。但需注意:

1) 若未来有人误修改了子包文件且未保持与原始文件同步,可能引入不一致;
2) git mv 检测到的重命名保留了 paged.py 的历史,但 base.pytoken.py 需要 -C 选项追溯历史;
3) 如果存在未发现的隐式导入(如动态导入路径),可能中断。但作者通过 __init__.py 的 re-export 和 grep 验证了所有外部导入,风险已控制。

对用户:无影响,API 完全向后兼容。对开发者:代码结构更清晰,每个文件职责单一,降低认知负担;新增分配器只需在子包中添加文件并更新 __init__.py。对系统:无性能影响,因为纯导入变更未改变运行时行为。

纯机械搬迁无逻辑变化 向后兼容导入 git blame 需 -C 选项用于新文件

关联 Issue

未识别关联 Issue

当前没有检测到明确关联的 Issue 链接,后续同步到相关引用后会出现在这里。

完整报告

参与讨论