Как я могу распространять и ловить ошибки, брошенные в другой поток в Raku? - PullRequest
9 голосов
/ 31 марта 2020

Каков наилучший способ распространения ошибок из отдельного потока (например, начальный блок, Pro c :: Asyn c или подпункт, содержащий их). Простое завершение кода, который раскручивает новый поток в блок try / CATCH, не работает, а использование await работает только в зависимости от возвращаемого значения подпрограммы (ie. Sub, возвращающий self, не будет работать с подходом await ).

Ответы [ 3 ]

6 голосов
/ 31 марта 2020

Используйте await.

Например, замените эти три строки в вашем коде:

foo;
bar;
baz;

на:

await foo, bar, baz;
5 голосов
/ 31 марта 2020

Теоретически, этот код должен d ie:

Начиная с версии 6.d языка префикс оператора 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 

В этом случае это странно ситуация, потому что вы не утопаете обещание (вы его возвращаете), но в конечном итоге вы его потопили, потому что вы выполняете его в пустом контексте.

Та же документация дает вам решение: не гасите контекст:

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

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

Поскольку ваша программа не d ie, я бы сказал, что вы находитесь во второй ситуации. По какой-то причине он не затонул. Но какова бы ни была ситуация, решение остается тем же: вам нужно перехватить исключение внутри одного и того же блока кода.

Решение: await обещание (которое его не поглотит) или назначить его какой-либо переменной , так что окружающий код тоже умирает. Но, отвечая на ваш OP, нет, вы не можете перехватить исключение из другого потока, так же, как вы не можете перехватить исключение из другого блока.

4 голосов
/ 15 апреля 2020

Следуя соглашению, используемому в 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;
...