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 不仅仅是一个被动的数据结构,而是一个主动的、有行为的状态管理器,从而使整个系统的代码更加健壮、清晰和易于维护。

相关推荐
Poetinthedusk7 小时前
设计模式-命令模式
windows·设计模式·c#·wpf·命令模式
雨中飘荡的记忆8 小时前
设计模式之桥接模式:从原理到实战
设计模式
北海屿鹿8 小时前
设计模式概述
设计模式
真夜10 小时前
发布观察者模式使用场景记录
设计模式
会员果汁12 小时前
4.设计模式-代理模式
设计模式·代理模式
有一个好名字13 小时前
设计模式-代理模式
java·设计模式·代理模式
catchadmin14 小时前
PHP 之高级面向对象编程 深入理解设计模式、原则与性能优化
设计模式·性能优化·php
郝学胜-神的一滴14 小时前
使用EBO绘制图形:解锁高效渲染与内存节省之道
c++·qt·游戏·设计模式·系统架构·图形渲染
冷崖15 小时前
原型模式-创建型
设计模式·原型模式
Poetinthedusk15 小时前
设计模式-单例模式
单例模式·设计模式