Сначала о выводе исключения, выданного из await
.При сбое асинхронной операции есть два интересных момента:
- Где в программе мы хотели получить результат операции
- Где в программе возникла проблема, которая означала операциюне может быть выполнена
Первая часть информации указывает местоположение await
, и трассировка стека относится к этому.Вторая часть о том, почему исключение было повторно выброшено await
, и указывает на проблему, которую необходимо исправить.
Проблема в этом случае состоит в том, что метод path
вызывается дляобъект, у которого его нет.Это благодаря .resume
, что не имеет смысла.Исключение указывает, что невозможно получить значение из канала.Его возобновление означает, что тело цикла выполняется с неопределенным значением в $file
, в котором отсутствует метод path
, что приводит к ошибке.(В качестве отступления: очень, очень редко .resume
является правильным ответом.)
Наименьшее исправление в коде - заменить .resume
на last
, что завершает итерацию, когдаканал закрыт:
my @workers = (^$N).map: {
start {
while my $file = $dir-channel.receive() {
say $file.path;
CATCH {
when X::Channel::ReceiveOnClosed { last }
}
}
}
}
Тем не менее, гораздо проще преобразовать Channel
в итеративный Seq
.Это автоматически обрабатывает завершение итерации, когда Channel
закрывается, поэтому нет возни с исключениями:
my @workers = (^$N).map: {
start {
for $dir-channel.Seq -> $file {
say $file.path;
}
}
}
А так как start
является префиксом оператора, который в дальнейшем сокращается до:
my @workers = (^$N).map: {
start for $dir-channel.Seq -> $file {
say $file.path;
}
}
Я понимаю, что это была, вероятно, упрощенная версия более интересной проблемы, или, возможно, она была сделана для изучения различных концепций параллелизма Perl 6, но весь лот можно было бы заменить на:
sub MAIN( Str $dir = ".", Int :$N = 4 ) {
race for dir($dir).race(batch => 1, degree => $N) -> $file {
say $file.path;
}
}
, который имеетта же семантика, но экономит запуск и управление работниками, но при этом контролирует количество работников и обеспечивает одинаковое распределение файлов среди работников.