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


9

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


Может быть fooи здесь barможно устранить?
jjmerelo

1
У меня все еще есть проблемы с этим сценарием ... это просто невозможно в Раку и требует реструктуризации реальных классов? Это не было бы идеально , потому что я не хочу конкретную обработку ошибок приложений в классах , которые могут быть повторно использованы в другом месте ...
ryn1x

@ ryn1x Предлагаю вам восстановить этот вопрос до первоначального вида. Затем добавьте примечание в начале, объясняющее, что, хотя некоторые из наших ответов решили проблему, изложенную в тексте вашего вопроса, вы на самом деле искали что-то более общее. Кроме того, хотя ответ, который вы приняли, был более общим, с тех пор вы пришли к выводу, что он все еще не был достаточно общим. Кроме того, что вы пытались получить награду, в сочетании с просьбой об общности, но это не помогло. Затем напишите новый вопрос, ссылаясь на него, с примером, который, по вашему мнению, иллюстрирует проблему.
Райп

Текущий ответ для меня вполне достаточен. Я изменил вопрос, потому что он становился слишком длинным и конкретным для тех, кто здесь оказался.
ryn1x

Ответы:


6

Использование await.

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

foo;
bar;
baz;

с:

await foo, bar, baz;

Это работает, но не соответствует моей реальной проблеме, потому что foo, bar и baz на самом деле являются методами, которые возвращают себя. Я обновил вопрос и пример.
ryn1x

5

Теоретически этот код должен умереть :

Начиная с версии 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";

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

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


Спасибо за все это. Я на самом деле должен быть более конкретным, чем в моем ОП. Я не вызываю в контексте приемника, и ожидающее решение также не работает, потому что функции из OP на самом деле являются методами, которые возвращают себя. Я обновил вопрос и пример.
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;
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.