You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

共享Supply是否可同时运行多个tap块?附代码验证分析

共享Supply能否同时运行多个tap块?

答案是可以,但这里有个关键细节需要理清:共享Supply的作用是让多个tap订阅同一份事件流(每个事件会分发给所有订阅的tap),但默认情况下,tap的回调处理是同步执行的——如果某个tap的逻辑耗时很长,会阻塞其他tap的处理,甚至导致部分事件来不及处理就随程序结束而中断。

我们结合你给出的例子来拆解:

非共享Supply的情况

先看你提供的第一个代码片段:

my $supply = Supply.interval(0.2);
my $tap = $supply.tap: { say "1 $^a"; sleep 5; };
sleep 5;

这里Supply.interval(0.2)会每隔0.2秒生成一个事件,但因为没有调用.share,这个Supply是“冷”的——只有当有tap订阅时才开始生成事件。不过你这里只有一个tap,所以事件会依次发给它。但因为tap里的sleep 5是阻塞操作,程序主流程的sleep 5结束后就会退出,而tap里的回调还在sleep,不过实际输出有25行(对应5秒内的所有事件),这是因为interval生成的事件会被暂存,当回调的sleep结束后,会快速处理完积压的所有事件,直到程序终止。

共享Supply的情况

当你把Supply改成.share后,它变成了“热”Supply——不管有没有tap订阅,事件都会持续生成(或者说,新的tap会从当前时间点开始接收后续事件)。但默认的tap回调还是同步执行的,比如如果我们加第二个tap:

my $supply = Supply.interval(0.2).share;
my $tap1 = $supply.tap: { say "Tap 1: $^a"; sleep 5; };
my $tap2 = $supply.tap: { say "Tap 2: $^a"; };
sleep 5;

此时,每个事件会先触发tap1的回调,等它的sleep 5完成后,才会触发tap2的回调。这就导致tap2的输出会严重滞后,而且程序主流程的sleep 5结束后,大部分事件的处理还没完成,会随程序终止而中断。

让多个tap同时运行的正确姿势

如果想让多个tap的回调同时异步执行,不需要阻塞彼此,你可以把tap里的耗时逻辑放到start块里,启动一个异步任务:

my $supply = Supply.interval(0.2).share;
my $tap1 = $supply.tap: { start { say "Tap 1: $^a"; sleep 5; } };
my $tap2 = $supply.tap: { say "Tap 2: $^a"; };
sleep 6; # 多等1秒,确保tap1的异步任务能完成

这样,tap1的回调会立即启动一个异步线程去处理sleep逻辑,不会阻塞tap2的回调执行,两个tap就能同时处理每个事件了。

总结一下:共享Supply本身支持多个tap订阅,但要让tap的处理同时运行,需要手动将耗时逻辑放到异步上下文里,避免阻塞事件流的分发和其他tap的执行。

内容的提问来源于stack exchange,提问作者brian d foy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 06:38:37