Slime异步原理(单例设计模式)5

Slime异步原理(单例设计模式)4

你又提出了一个非常好的问题,这涉及到代码的组织结构和职责划分,是衡量代码设计优劣的重要方面。

submit_generate_tasks 函数放在 GenerateState 类下,而不是作为一个独立的全局函数,主要有以下几个原因:

1. 职责单一与高内聚(Single Responsibility & High Cohesion)

GenerateState 类的核心职责是管理所有与生成过程相关的状态 。这不仅包括像 tokenizersemaphore 这样的静态资源,也包括像 pendings(待处理任务集合)和 remaining_batch_size(剩余批次大小)这样的动态状态。

  • submit_generate_tasks 函数的核心作用是什么?
    • 它接收一批样本 (samples)。
    • 为这批样本创建 asyncio.Task
    • 将这些任务添加到 self.pendings 集合中进行跟踪。
    • 更新 self.remaining_batch_size 计数。

可以看到,这个函数的操作与 GenerateState 内部的状态变量 (pendings, remaining_batch_size) 紧密相关 。将函数和它操作的数据放在一起,是"高内聚"原则的体现。这使得 GenerateState 成为一个完整、独立的组件,负责管理从任务提交到状态跟踪的整个生命周期。

反例:如果不放在类里会怎么样?

假设我们把它作为一个全局函数:

python 复制代码
# 全局函数版本
def submit_generate_tasks_global(state: GenerateState, samples: list[list[Sample]]):
    for group in samples:
        state.pendings.add(
            asyncio.create_task(...)
        )
    state.remaining_batch_size += len(samples)

# 在其他地方调用
state = GenerateState(args)
samples = data_source(...)
submit_generate_tasks_global(state, samples)

这样做虽然功能上可行,但有几个缺点:

  • 职责不清晰GenerateState 变成了纯粹的数据容器,而操作这些数据的逻辑却散落在外部,破坏了类的封装性。
  • 增加了调用复杂度 :每次调用都需要同时传递 state 对象和 samples,而作为类方法,只需要传递 samples (self 是隐式传递的)。
  • 维护困难 :如果未来 GenerateState 内部状态管理的方式发生改变(比如 pendingsset 变成了 dict),你不仅要修改 GenerateState 类,还需要去查找并修改所有像 submit_generate_tasks_global 这样直接操作其内部状态的外部函数。

2. 封装与信息隐藏(Encapsulation & Information Hiding)

通过将 submit_generate_tasks 作为 GenerateState 的一个方法,外部调用者(比如 generate_rollout_async 函数)只需要知道"如何提交任务",而不需要关心"任务是如何被跟踪和管理的"。

  • 外部视角state.submit_generate_tasks(samples) ------ 这是一个清晰的指令,意为"状态管理器,请帮我处理这批任务"。
  • 内部实现 :这个方法内部具体是把任务加到一个 set 里,还是一个 list 里,还是一个更复杂的数据结构里,对于外部调用者来说是透明的。这种信息隐藏使得代码更容易维护和重构。

如果未来我们想增加更复杂的逻辑,比如在提交任务时进行优先级排序,或者记录任务的提交时间,我们只需要修改 submit_generate_tasks 这个方法内部的实现,而所有调用它的代码都无需改动

3. 代码可读性与面向对象思想

将相关的功能组织在同一个类中,使得代码结构更清晰,更符合人类的思维习惯。当我们阅读 GenerateState 类的代码时,我们可以一目了然地看到它包含了哪些状态 (__init__),以及可以对这些状态执行哪些操作(reset, submit_generate_tasks)。

这就像一个"任务管理器"对象,它有自己的属性(任务列表、剩余任务数),也有自己的行为(提交任务、重置状态)。这比将属性和行为分散在代码各处要更容易理解。

总结

submit_generate_tasks 放在 GenerateState 类下,是遵循良好软件设计原则的体现:

原则 在此处的体现
高内聚 函数和它紧密操作的数据(pendings, remaining_batch_size)被组织在一起。
低耦合 外部代码通过一个稳定的接口与状态管理器交互,而不需要了解其内部实现细节。
封装性 状态管理的具体逻辑被隐藏在类的方法内部,保护了内部状态的完整性。
职责单一 GenerateState 作为一个整体,负责"管理生成过程的状态"这一单一职责。

所以,这个设计决策让 GenerateState 不仅仅是一个被动的数据结构,而是一个主动的、有行为的状态管理器,从而使整个系统的代码更加健壮、清晰和易于维护。

相关推荐
苏渡苇6 小时前
优雅应对异常,从“try-catch堆砌”到“设计驱动”
java·后端·设计模式·学习方法·责任链模式
短剑重铸之日7 小时前
《设计模式》第十一篇:总结
java·后端·设计模式·总结
feasibility.7 小时前
AI 编程助手进阶指南:从 Claude Code 到 OpenCode 的工程化经验总结
人工智能·经验分享·设计模式·自动化·agi·skills·opencode
BD_Marathon8 小时前
七大设计原则介绍
设计模式
YigAin10 小时前
Unity23种设计模式之 享元模式
设计模式·享元模式
范纹杉想快点毕业1 天前
实战级ZYNQ中断状态机FIFO设计
java·开发语言·驱动开发·设计模式·架构·mfc
茂桑1 天前
DDD领域驱动设计-基础设施层
设计模式·架构
小温冲冲1 天前
通俗且全面精讲工厂设计模式
设计模式
进击的小头1 天前
设计模式与C语言高级特性的结合
c语言·设计模式
小温冲冲1 天前
通俗且全面精讲单例设计模式
开发语言·javascript·设计模式