🐳 第五章 Cordis让插件能够动态组合
📄 一句话概括

动态组合的第一条硬规矩是时间维度的:变化必须能被撤下——装上、在场、撤下三段都有账要记,脏的撤下会留下【悬空引用】。

📝 本节和前面几节的关系

第四章证明了【能装、能换、能停】,第五章回答这套机制凭什么不会乱。第一条答案就在时间维度上。

一、三段生命周期,三笔账

三段缺一不可:只装不记,撤不下;只改不声明,恢复不了;只撤不清,留尾巴。

二、算一笔账:脏撤下的代价

会话里装了 3 件插件,撤掉 1 件——

那 0.5 件就是悬空引用:占着位置、提供不了服务、还可能在某个时刻突然报错。

悬空引用的麻烦在于发现得晚——出错的位置往往离出错的根很远。

三、为什么写成【必须】而不是【最好】

Agent 会话的常态是频繁生灭:一个会话几十次装卸都正常。

在这种频率下,【偶尔撤不干净】不是小概率事件,是必然事件——十次里漏一次,一天就是几十个悬空引用。

所以教材把【生命周期结束时,变化也必须被撤下】写成硬规矩:不是风格偏好,是频率决定的生存条件。

四、撤下的标准是什么

回到装它之前的状态。具体到三件事:

三条都做到,这次装卸才是【干净的】——这也是 5.8 实验里【回来】那一步敢写 disabled: false 的底气。

五、动手 Demo:时间维度——变化必须能被撤下

三段账、一笔悬空引用的算术:

stages = [("装上", "记录实例、声明影响范围"),
          ("在场", "按声明提供服务"),
          ("撤下", "清理、恢复现场")]
for a, b in stages:
    print("  %-4s %s" % (a, b))
print()
print("  干净的撤下: 3 -> 2, 其余 2 件不受影响")
print("  脏的撤下:   账面 3 -> 2, 实际 2.5(悬空引用)")

实跑输出:

--------------------------------------------------------------------
时间维度——变化必须能被撤下
--------------------------------------------------------------------
  动态组合的时间维度一句话:**变化必须能被撤下**。
  一件插件从装上到撤下,系统在每个阶段都有账要记:

  阶段     系统做了什么               没做会怎样
  -------------------------------------------------------
  装上     记录实例、声明影响范围     装完就忘,撤不下来
  在场     按声明提供服务             改了别人却不留痕
  撤下     清理、恢复现场             留下悬空引用
  -------------------------------------------------------

  算一笔账:会话里装了 3 件插件,撤掉 1 件——

    干净的撤下    其余 2 件不受影响,账面 3 -> 2
    脏的撤下      引用还在,账面 3 -> 2,实际 2.5

  【那 0.5 件】就是悬空引用:占着位置,提供不了服务,还可能报错。
  所以教材把【能撤下】写成硬要求,不是好习惯。

悬空引用发现得晚——出错位置离出错根源很远,排查极痛苦;这是脏撤下的真实代价。 会话生灭的高频让【偶尔漏一次】变成必然——硬规矩是频率逼出来的。 撤下的三条标准(注销、恢复、释放)可以当检查清单用。

30 秒实验

  1. 复述三段生命周期,各配一句【没做会怎样】。
  2. 想一个你见过的【卸载不干净】:哪个软件卸完还留了一堆服务?
  3. 把撤下的三条标准背下来,下一节的 Fiber 会把它们变成账本条目。

常见误区

  1. 错误:撤下就是把它从列表里删掉。——纠正:要恢复现场——注销注册项、还原改动、释放资源,三件都做才算干净。
  2. 错误:偶尔撤不干净无伤大雅。——纠正:会话生灭高频下漏一次是必然,悬空引用会持续累积。
  3. 错误:悬空引用会立刻报错,好发现。——纠正:恰恰相反——它安静地占着位,出错位置离根源很远。
自测三问(点开对答案) 1. 动态组合时间维度的硬规矩是什么? —— **生命周期结束时,变化也必须被撤下**——回到装它之前的状态。 2. 撤下的三条标准是什么? —— 注册项被注销、改动被恢复、资源被释放。 3. 为什么写成【必须】而不是【最好】? —— 会话频繁生灭让漏撤成为**必然事件**,悬空引用会累积——这是生存条件不是偏好。

相关笔记