Rakuの別のスレッドでスローされたエラーを伝播およびキャッチするにはどうすればよいですか?


9

別のスレッド(たとえば、開始ブロック、Proc :: Async、またはこれらを含むサブルーチン)からエラーを伝播する最良の方法は何ですか。新しいスレッドをスピンオフするコードをtry / CATCHブロックで単にラップするだけでは機能せず、awaitの使用は、サブルーチンの戻り値に応じてのみ機能します(つまり、subがselfを返すと、awaitアプローチでは機能しません)。


たぶんfoobarここで排除できますか?
jjmerelo

1
私はまだこのシナリオで問題を抱えています... Rakuでは単に不可能であり、実際のクラスを再構築する必要がありますか?他の場所で再利用できるクラスでアプリケーション固有のエラー処理をしたくないので、それは理想的ではありません...
ryn1x

@ ryn1xこの質問を元の形式に戻すことを検討することをお勧めします。次に、冒頭にメモを追加してください。私たちの回答の中には、質問の本文に記載されている問題の説明を解決したものもありますが、実際にはもっと一般的なものを探していました。さらに、あなたが受け入れた答えはより一般的でしたが、それでもそれはまだ十分に一般的ではなかったと結論づけました。さらに、より一般性を求めることと相まって、賞金を試したが、それは役に立たなかった。次に、この問題にリンクし、問題を説明すると思われる例を使用して、新しい質問を記述します。
レイフ

現在の答えは私には完全に十分です。質問が長くなりすぎて、ここで終わる人には具体的になったので、質問を変更しました。
ryn1x

回答:


6

を使用しawaitます。

たとえば、コードの次の3行を置き換えます。

foo;
bar;
baz;

と:

await foo, bar, baz;

これは機能しますが、foo、bar、およびbazは実際にはselfを返すメソッドであるため、実際の問題には対応していません。質問と例を更新しました。
ryn1x

5

理論的には、そのコードは死ぬはずです:

言語の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に応答すると、いいえ。別のスレッドからの例外をキャッチすることはできません。同じように、別のブロックからの例外をキャッチすることもできません。


このすべてをありがとう。私は実際には私のOPよりも具体的にする必要があります。私はシンクコンテキストで呼び出していません。また、OPの関数は実際には自己を返すメソッドであるため、awaitソリューションも機能しません。質問と例を更新しました。
ryn1x

4

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;
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.