Bagaimana saya bisa menyebarkan dan menangkap kesalahan yang dilemparkan ke utas lain di Raku?

9

Apa cara terbaik untuk menyebarkan kesalahan dari utas terpisah (mis. Blok start, Proc :: Async, atau sub yang mengandung ini). Cukup dengan membungkus kode yang memutar utas baru dalam blok coba / CATCH tidak berfungsi, dan menggunakan menunggu hanya berfungsi tergantung pada nilai balik dari sub rutin (mis. Diri yang kembali tidak akan bekerja dengan pendekatan menunggu).

ryn1x
sumber
Mungkin foodan barbisa dihilangkan di sini?
jjmerelo
1
Saya masih mengalami masalah dengan skenario ini ... apakah itu tidak mungkin di Raku dan membutuhkan restrukturisasi kelas yang sebenarnya? Itu tidak akan ideal karena saya tidak ingin penanganan kesalahan khusus aplikasi di kelas yang dapat digunakan kembali di tempat lain ...
ryn1x
@ ryn1x Saya sarankan Anda mempertimbangkan mengembalikan pertanyaan ini ke bentuk aslinya. Kemudian tambahkan catatan di awal yang menjelaskan bahwa, meskipun beberapa jawaban kami memecahkan pernyataan masalah yang diberikan dalam tubuh pertanyaan Anda, Anda sebenarnya mencari sesuatu yang lebih umum. Lebih jauh, bahwa walaupun jawaban yang Anda terima lebih umum, Anda telah menyimpulkan bahwa jawabannya masih belum umum. Lebih jauh, Anda mencoba hadiah, ditambah dengan meminta lebih banyak generalisasi, tetapi itu tidak membantu. Kemudian tulis pertanyaan baru , tautkan kembali ke pertanyaan ini, dengan contoh yang menurut Anda menggambarkan masalahnya.
raiph
Jawaban saat ini benar-benar cukup untuk saya. Saya mengubah pertanyaan karena sudah terlalu lama dan spesifik untuk siapa pun yang berakhir di sini.
ryn1x

Jawaban:

6

Gunakan await.

Misalnya, ganti tiga baris ini dalam kode Anda:

foo;
bar;
baz;

dengan:

await foo, bar, baz;
raiph
sumber
Ini bekerja, tetapi tidak skala untuk masalah saya yang sebenarnya karena foo, bar, dan baz sebenarnya adalah metode yang mengembalikan diri. Saya memperbarui pertanyaan dan contoh.
ryn1x
5

Secara teoritis, kode itu harus mati :

Pada versi bahasa 6.d, awalan pernyataan awal yang digunakan dalam konteks sink akan secara otomatis melampirkan pengendali pengecualian. Jika pengecualian terjadi pada kode yang diberikan, itu akan dicetak dan program kemudian akan keluar, seperti jika dilemparkan tanpa awalan pernyataan awal yang terlibat.

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 

Dalam hal ini adalah situasi yang aneh karena Anda tidak menenggelamkan janji (Anda mengembalikannya), tetapi akhirnya Anda menenggelamkannya karena Anda menjalankannya dalam konteks yang tidak jelas.

Dokumentasi yang sama memberi Anda solusinya: jangan tenggelamkan konteksnya:

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

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

Karena program Anda tidak mati, saya akan mengatakan Anda berada dalam situasi kedua. Untuk beberapa alasan, itu tidak hangus. Tapi apa pun situasinya, solusinya sama: Anda perlu menangkap pengecualian di dalam blok kode yang sama.

Solusi: awaitjanji (yang tidak akan menenggelamkannya) atau menetapkannya ke beberapa variabel, sehingga kode di sekitarnya mati juga. Tetapi menanggapi OP Anda, tidak, Anda tidak dapat menangkap pengecualian dari utas lainnya, dengan cara yang sama Anda tidak dapat menangkap pengecualian dari blok lain.

jjmerelo
sumber
Terima kasih untuk semua ini. Saya sebenarnya harus lebih spesifik daripada di OP saya. Saya tidak memanggil konteks wastafel dan solusi menunggu juga tidak berfungsi karena fungsi dari OP sebenarnya adalah metode yang mengembalikan diri. Saya memperbarui pertanyaan dan contoh.
ryn1x
4

Mengikuti konvensi yang digunakan dalam Go untuk mengeluarkan kesalahan dari rutinitas menggunakan saluran, saya menemukan pendekatan yang sama untuk bekerja di Raku. Seseorang dapat menggunakan Saluran untuk mengirim kesalahan dari kode asinkron untuk ditangani oleh utas utama.

Contoh:

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;
ryn1x
sumber