Effect fork 的 uninterruptible 选项怎么用?
我给一个 sleep 30 毫秒的子 fiber 设了 uninterruptible: true,5 毫秒后去中断它,Fiber.interrupt 等了 31 毫秒才返回;不设的话,6 毫秒就回来了。
uninterruptible: true 让子 fiber 整个不可中断,中断请求被推迟到它自然结束,调用方会被阻塞到那时。它适合「必须做完的收尾任务」,不能用在可能永远不结束的任务上。
这个选项和 startImmediately 一样,是 fork 系列函数的第二个选项,类型是 boolean | "inherit"。中断在 Effect 里是一等公民,它与失败的区别见 Effect 里中断和失败有什么区别?。下面对比三种取值。
三种取值有什么区别?
我用一个会 sleep 的子 fiber,让父 fiber 5 毫秒后调用 Fiber.interrupt,对比三种取值:
import { Effect, Fiber } from "effect"
const probe = async (label: string, options?: { readonly uninterruptible?: boolean | "inherit" }) => {
const log: Array<string> = []
const body = Effect.gen(function*() {
log.push("start")
yield* Effect.sleep(30)
log.push("finished")
}).pipe(Effect.onInterrupt(() => Effect.sync(() => { log.push("interrupted") })))
const t0 = performance.now()
await Effect.runPromise(Effect.gen(function*() {
const fiber = yield* Effect.forkChild(body, { startImmediately: true, ...options })
yield* Effect.sleep(5)
yield* Fiber.interrupt(fiber)
}))
console.log(label.padEnd(26), log, `interrupt returned after ${Math.round(performance.now() - t0)}ms`)
}
await probe("default")
await probe("uninterruptible: true", { uninterruptible: true })
await probe("uninterruptible: inherit", { uninterruptible: "inherit" })输出(耗时每次略有浮动):
default [ 'start', 'interrupted' ] interrupt returned after 6ms
uninterruptible: true [ 'start', 'finished' ] interrupt returned after 31ms
uninterruptible: inherit [ 'start', 'interrupted' ] interrupt returned after 6ms- 默认和
"inherit"在这个场景下一致,子 fiber 被中断。 true让子 fiber 整个不可中断:中断请求被推迟,Fiber.interrupt要等它自然结束才返回(31 毫秒,而不是 6 毫秒)。"inherit"是继承父 fiber 当前的可中断状态。我另外在Effect.uninterruptible(...)包裹的父 fiber 里 fork,结果子 fiber 同样没有被中断,输出的是finished。
什么任务该设 uninterruptible: true?
适合「必须做完的收尾任务」,比如落盘、提交 offset。代价很直接:它会让中断调用方被阻塞。对「可能永远不结束」的任务,千万不要这么设,否则关闭流程会卡住。
Scope 关闭时,它也会推迟中断吗?
我不知道。我只验证了通过 Fiber.interrupt 触发的中断;它对 Scope 关闭时的中断是否同样推迟,我没有跑过,不写成结论。如果你的子 fiber 是用 forkScoped 或 forkIn 挂在 Scope 上的,先自己跑一遍确认。
四个 fork 各自挂在哪、什么时候该用哪个,见 Effect 的四个 fork 该怎么选?。
验证环境是 effect 4.0.5。三种取值的对比输出,以及"inherit"在Effect.uninterruptible包裹的父 fiber 里的表现,都是我在这个版本上跑出来的,耗时每次略有浮动。Scope 关闭时的中断是否同样被推迟,我没有验证;落盘、提交 offset 这类用途是我的建议,不是跑出来的结论。