acquireRelease 的获取和释放能被中断吗?
一个连接获取到一半,fiber 被中断了。资源到底拿到没有?有没有占着什么?如果运行时在这里随便打断,你既无法清理,也无法确认状态。
答案是:acquireRelease 的获取步骤默认不可中断,释放步骤也不会被中断。获取到一半被中断时,获取会先跑完,随后立刻执行释放,Fiber.interrupt 要等这些都结束才返回。
这么设计的理由很朴素:把这两步保护起来,“获取与释放成对”这个承诺才站得住。如果你还不熟悉 Scope 与 finalizer 的关系,先看 Effect 怎么保证资源一定被释放。下面讲细节。
获取一半被中断,会发生什么?
我在本地验证过:获取到一半被中断时,获取会先跑完,随后立刻执行释放,Fiber.interrupt 要等这些都结束才返回。
为什么不直接打断?因为打断在获取中途,你既没有拿到资源,也不知道有没有占着什么,无法清理。获取默认不可中断,有一个 interruptible 选项可以改变这一默认行为。
释放为什么不会被中断?
释放到一半被打断,就等于泄漏。所以释放步骤同样受保护,不会被中断。
释放函数可以失败吗?
释放动作的类型限定它不能有可预期的失败,也就是 E 为 never。这是有意为之:清理是兜底,兜底再失败,没有人可以接着处理。清理里可能出的问题,应该在释放函数内部自己消化,比如记录日志、忽略,而不是向外抛。不要在释放里抛业务错误,类型已经不允许,别想着绕开。
要不要自己加 Effect.uninterruptible?
通常不需要。acquireRelease 已经为获取与释放做了正确的保护。大范围使用 Effect.uninterruptible 的风险是:不可中断的区域内取消不会生效,运行时间过长会让整个系统“关不掉”。只在确有必要的窄小区间使用。
本文整理自一篇 Effect 教程章节,没有记录 effect 的版本号。“获取到一半被中断时获取先跑完、再释放、Fiber.interrupt等其结束”这一行为我在本地跑过;interruptible选项、释放不可被中断、释放 E 为 never 等说法按原章节整理,没有单独验证,请以你所用版本的文档为准。