Effect 里限并发、限速率、限节拍该用哪个?

「限流」在代码里至少指三件不同的事:同时最多几个在跑、单位时间最多放行几个、一个循环每隔多久跑一次。混用最常见的后果是:想限速却用了信号量,想按用户限流却只有一个全局计数。

Effect 里 Semaphore 限并发,Schedule 限单个循环的节拍,RateLimiter 限多调用方共享的速率配额,三者回答的是不同问题,不能互相替代。

下面逐个说它们各自管什么、不管什么,再给一个选型顺序。Semaphore 的基本用法见 Effect 里怎么用 Semaphore 限制并发数?,RateLimiter 的完整用法见 Effect 的 RateLimiter 怎么按 key 限速?。

Semaphore 能当限速器用吗?

不能。Semaphore 限的是并发:同时最多 N 个在飞。它不关心速率。我试过 10 个瞬间完成的任务通过 2 个许可,总耗时几乎为零,速率完全没有被限制。

它适合保护连接池、文件句柄、有并发上限的下游。

Schedule 和 RateLimiter 有什么区别?

Schedule 限的是节拍:一个循环按什么节奏重复。例如 Effect.repeat({ schedule: Schedule.spaced("50 millis"), times: 4 }) 让同一个循环两次执行之间间隔 50ms,我试过约 200ms 完成 5 次。

它约束的是「这一个调用链」,不是「所有调用者共享的额度」。Schedule 本身的用法见 Effect 重试与 Schedule:退避、抖动、repeat、超时与限流。

RateLimiter 限的是速率配额:多个调用方、多个 key 共享一份额度,可以选择超限时失败或排队,存储可以换成跨进程的。

该怎么选?

选型顺序可以这样走:

  1. 担心的是同时占用资源,用 Semaphore
  2. 只有一个循环,需要控制节奏,用 Schedule
  3. 有多个调用方共享额度,或者需要按用户、租户、API key 分别计数,或者要跨进程,用 RateLimiter
  4. 既要限并发又要限速率,两者叠加:外层 RateLimiter 决定什么时候可以开始,内层 Semaphore 决定同时跑几个

选型时还要算上稳定性:RateLimiter 在 4.0.5 里标注为 @stability unstable,Semaphore 是 @stability stable。如果你只需要进程内的简单限速,一个 Semaphore 加 Schedule.spaced 往往够用,也更稳定。

版本是 effect 4.0.5。Semaphore 与 Schedule.spaced 的耗时数字是我在这个版本上跑出来的;叠加使用的顺序(外层 RateLimiter、内层 Semaphore)是我的设计建议,没有单独写示例运行过。稳定性标注读自该版本的 JSDoc,后续版本可能变化。