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

Raku中从whenever块内部修改监听Supply目标不生效问题咨询

问题行为定性

该行为完全符合Raku的语言规范。

核心语义误解

你对whenever关键字的语义存在认知偏差:whenever $supply { ... } 仅会对传入的$supply表达式求值一次,拿到对应的Supply/Channel实例后就会直接订阅该实例,后续你修改存储实例的变量$currently-listening-to,不会改变已经建立的订阅关系,所以会持续收到$c1的消息。而$other-var是普通可变变量,修改它自然会生效,这就是两者表现不一致的原因。
该逻辑对supply块、react块、Channel场景通用,所以你在多个并发结构下都复现了相同行为。

动态切换监听源的实现方案

要实现可控的源切换,你需要手动管理订阅生命周期,切换时关闭旧订阅,再为新Supply建立新订阅即可,参考实现如下:

my $c1 = Supplier.new;
my $c2 = Supplier.new;

my $s = supply {
    my $active-tap;
    my $other-var = 'foo';
    # 初始订阅c1
    $active-tap = whenever $c1.Supply -> $msg {
        say "got: $msg";
        if $msg.starts-with('3') {
            say "listening to something new";
            # 关闭旧的c1订阅
            $active-tap.close;
            $other-var = 'bar';
            say $other-var;
            # 订阅新的c2
            $active-tap = whenever $c2.Supply -> $new-msg {
                say "got: $new-msg";
                # 可在此处添加自定义切换逻辑、错误处理逻辑,可控性远高于内置的migrate
            }
        }
    }
}

$s.tap;

for ^7 {
    $c1.emit: "$_ from \$c1";
    $c2.emit: "$_ from \$c2";
}
sleep 1;

运行上述代码即可符合你的预期:收到3 from $c1之后,就会开始接收$c2的后续消息。

适配监管场景的方案

针对你要实现的Erlang风格进程监管逻辑,可以直接复用上述思路:将每个子进程对应的Supply和订阅Tap都存入状态变量,当监听到子进程异常消息时,先调用close关掉异常子进程的订阅,杀死异常子进程,启动新子进程后再为新子进程的Supply建立whenever订阅即可,完全可以满足动态监听新子进程的需求。

内容的提问来源于stack exchange,提问作者codesections

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.01 10:15:04