Як я можу розповсюджувати та фіксувати помилки, викинуті в інший потік у Раку?


9

Який найкращий спосіб поширити помилки з окремої нитки (наприклад, стартовий блок, Proc :: Async або підміст, що містить їх). Просте загортання коду, який відкручує новий потік у блоці спробу / CATCH, не працює, а використання функція wait працює лише залежно від значення повернення підпрограми (т. Е. Суб-повернення self не працюватиме з підходом очікування).


Може, fooі barтут можна усунути?
jjmerelo

1
У мене все ще виникають проблеми з цим сценарієм ... це просто не можливо в Раку і вимагає реструктуризації фактичних класів? Це не було б ідеально, тому що я не хочу, щоб додатки
поводилися з

@ ryn1x Я пропоную розглянути можливість відновлення цього питання до його початкового вигляду. Потім на початку додайте примітку, пояснюючи, що, хоча деякі з наших відповідей вирішили проблему, подану в тілі вашого запитання, ви насправді шукали чогось більш загального. Далі, якщо відповідь, яку ви прийняли, була більш загальною, то ви зробили висновок, що вона все ще не є достатньо загальною. Крім того, ви спробували щедро, разом із проханням про більшу загальність, але це не допомогло. Потім напишіть нове запитання, посилаючись на це, із прикладом, на який, на вашу думку, ілюструє проблему.
raiph

Поточна відповідь мені цілком достатня. Я змінив питання, тому що він надто довгий і специфічний для тих, хто опинився тут.
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обіцянка (яка не затопить її) або призначте її якійсь змінній, щоб оточуючий код теж помер. Але, відповідаючи на ваш ОП, ні, ви не можете зловити виняток з іншого потоку, так само, як ви не можете вилучити виняток з іншого блоку.


Дякую за все це. Мені насправді потрібно бути більш конкретним, ніж у моїй ОП Я не закликаю в контексті раковини, і очікування рішення також не працює, оскільки функції з ОП - це фактично методи, які повертаються "я". Я оновив питання та приклад.
ryn1x

4

Дотримуючись конвенції, що використовується у програмі Go для передачі помилок із підпрограми руху за допомогою каналів, я знайшов той самий підхід до роботи в Раку. Канал можна використовувати для надсилання помилок із асинхронного коду, який обробляється основним потоком.

Приклад:

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.