別のスレッド(たとえば、開始ブロック、Proc :: Async、またはこれらを含むサブルーチン)からエラーを伝播する最良の方法は何ですか。新しいスレッドをスピンオフするコードをtry / CATCHブロックで単にラップするだけでは機能せず、awaitの使用は、サブルーチンの戻り値に応じてのみ機能します(つまり、subがselfを返すと、awaitアプローチでは機能しません)。
別のスレッド(たとえば、開始ブロック、Proc :: Async、またはこれらを含むサブルーチン)からエラーを伝播する最良の方法は何ですか。新しいスレッドをスピンオフするコードをtry / CATCHブロックで単にラップするだけでは機能せず、awaitの使用は、サブルーチンの戻り値に応じてのみ機能します(つまり、subがselfを返すと、awaitアプローチでは機能しません)。
回答:
理論的には、そのコードは死ぬはずです:
言語の6.dバージョンの時点で、シンクコンテキストで使用される開始ステートメントプレフィックスは、自動的に例外ハンドラーをアタッチします。指定されたコードで例外が発生した場合、その例外は出力され、プログラムは、開始ステートメントの接頭辞なしでスローされた場合と同様に終了します。
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
この場合、promiseをシンクしない(返す)ので奇妙な状況になりますが、voidコンテキストで実行しているため、最終的にシンクします。
同じドキュメントがあなたに解決策を与えます:コンテキストを沈めないでください:
# Don't sink it:
my $ = start { die }; sleep ⅓; say "hello"; # OUTPUT: «hello»
# Catch yourself:
start { die; CATCH { default { say "caught" } } };
sleep ⅓;
say "hello";
あなたのプログラムは死なないので、私はあなたが2番目の状況にいると言います。どういうわけか、沈んでいない。しかし、状況が何であれ、解決策は同じです。同じコードブロック内で例外をキャッチする必要があります。
解決策:await
プロミス(それをシンクしません)またはそれを変数に割り当てて、周囲のコードも死ぬようにします。しかし、OPに応答すると、いいえ。別のスレッドからの例外をキャッチすることはできません。同じように、別のブロックからの例外をキャッチすることもできません。
Goで使用されている規則に従って、チャネルを使用してgoルーチンからエラーを渡すと、Rakuでも同じアプローチが機能することがわかりました。チャネルを使用して、メインスレッドで処理される非同期コードからエラーを送信できます。
例:
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;
foo
、bar
ここで排除できますか?