【问题标题】:How can I propagate and catch errors thrown in another thread in Raku?如何传播和捕获 Raku 中另一个线程中抛出的错误?
【发布时间】:2020-03-30 23:59:14
【问题描述】:

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

【问题讨论】:

  • 或许foobar可以在这里去掉?
  • 我仍然遇到这种情况的问题...在 Raku 中根本不可能并且需要重组实际类?这并不理想,因为我不希望在可以在其他地方重用的类中进行特定于应用程序的错误处理......
  • 目前的答案对我来说完全足够了。我改变了这个问题,因为它对于最终来到这里的任何人来说都变得太长而且太具体了。

标签: raku


【解决方案1】:

使用await

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

foo;
bar;
baz;

与:

await foo, bar, baz;

【讨论】:

  • 这可行,但没有扩展到我的实际问题,因为 foo、bar 和 baz 实际上是返回自我的方法。我更新了问题和示例。
【解决方案2】:

理论上,那个代码should die:

从 6.d 版本的语言开始,在 sink 上下文中使用的 start 语句前缀将自动附加一个异常处理程序。如果在给定的代码中发生异常,它将被打印出来,然后程序将退出,就像在不涉及任何 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 

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

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

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

# Catch yourself: 
start { die; CATCH { default { say "caught" } } };
sleep ⅓;
say "hello";

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

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

【讨论】:

  • 感谢所有这些。我实际上需要比我的 OP 更具体。我没有在接收器上下文中调用,并且等待解决方案也不起作用,因为来自 OP 的函数实际上是返回 self 的方法。我更新了问题和示例。
【解决方案3】:

遵循 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;

【讨论】:

    猜你喜欢
    • 2012-05-08
    • 1970-01-01
    • 2011-06-25
    • 1970-01-01
    • 2018-02-25
    • 2019-09-17
    • 2011-01-25
    • 2022-07-26
    • 1970-01-01
    相关资源
    最近更新 更多