如何传播和捕获 Raku 中另一个线程中抛出的错误?

ryn*_*n1x 9 raku

从单独的线程(例如,开始块、Proc::Async 或包含这些的子程序)传播错误的最佳方法是什么。简单地将在 try/CATCH 块中分出新线程的代码包装起来是行不通的,并且使用 await 仅根据子例程的返回值起作用(即,子返回 self 不适用于 await 方法)。

rai*_*iph 6

使用await.

例如,替换代码中的这三行:

foo;
bar;
baz;
Run Code Online (Sandbox Code Playgroud)

和:

await foo, bar, baz;
Run Code Online (Sandbox Code Playgroud)


jjm*_*elo 5

从理论上讲,该代码应该死

从该语言的 6.d 版本开始,接收器上下文中使用的 start 语句前缀将自动附加异常处理程序。如果在给定的代码中发生异常,它将被打印出来,然后程序将退出,就像它在不涉及任何开始语句前缀的情况下抛出一样。

use v6.c;
start { die }; sleep ?; say "hello"; # OUTPUT: «hello?» 

use v6.d;
start { die }; sleep ?; say "hello";
# OUTPUT: 
# Unhandled exception in code scheduled on thread 4 
# Died 
#     in block  at -e line 1 
Run Code Online (Sandbox Code Playgroud)

在这种情况下,这是一个奇怪的情况,因为您没有沉没承诺(您正在返回它),但最终您沉没了它,因为您是在无效上下文中运行它。

相同的文档为您提供了解决方案:不要沉没上下文:

# Don't sink it: 
my $ = start { die }; sleep ?; say "hello"; # OUTPUT: «hello?» 

# Catch yourself: 
start { die; CATCH { default { say "caught" } } };
sleep ?;
say "hello";
Run Code Online (Sandbox Code Playgroud)

由于您的程序没有死,我会说您处于第二种情况。出于某种原因,它没有沉没。但不管是什么情况,解决方案都是一样的:你需要在同一个代码块中捕获异常。

解决方案:await承诺(不会沉没)或将其分配给某个变量,这样周围的代码也会死亡。但是响应您的 OP,不,您无法从另一个线程捕获异常,就像您无法从另一个块捕获异常一样。


ryn*_*n1x 4

遵循 Go 中使用通道将错误传递出 go 例程的约定,我发现在 Raku 中也可以使用相同的方法。可以使用 Channel 将错误从异步代码中发送出去,由主线程处理。

例子:

my $errors = Channel.new;

my $err-supply = $errors.Supply;
$err-supply.tap(-> $e {say "handle error: $e"});

start {
    die "something went horribly wrong";

    CATCH {
        default {
            $errors.send($_);
        }
    }
}

sleep 1;
Run Code Online (Sandbox Code Playgroud)