Курс языка программирования Raku / Функциональное, конкурентное, реактивное и веб-программирование / Конкурентное программирование / Каналы
Чтение после конца
Что произойдёт, если вызвать .receive больше раз, чем
есть значений? Ответ зависит от того, закрыт ли
канал.
Возьмём прежний пример с производителем и потребителем: фоновая задача отправляет три значения и закрывает канал. А что, если потребитель попросит четвёртое?
my $c = Channel.new;
start {
$c.send($_) for 1..3;
$c.close;
}
say $c.receive; # 1
say $c.receive; # 2
say $c.receive; # 3
say $c.receive; # одним получением больше, чем нужноНа закрытом канале лишнее получение бросает исключение
Закрытие не выбрасывает уже стоящие в очереди значения — три вызова
.receive выше по-прежнему вернут 1,
2 и 3. Но как только канал закрыт
и пуст, новых значений появиться уже не может, и,
вместо того чтобы позволить вам ждать вечно, Raku возбуждает
исключение:
Cannot receive a message on a closed channelЭто исключение X::Channel::ReceiveOnClosed. Оно скорее
полезно, чем досадно: оно недвусмысленно сообщает потребителю, что канал
вычерпан. На практике до него не доходит, если потреблять через
.list (который аккуратно останавливается на закрытии) или
крутить цикл лишь пока значения остаются, — оба способа показаны на
предыдущей странице.
На открытом канале лишнее получение блокирует выполнение
Если производитель канал так и не закрыл, .receive не
может знать, придёт ли ещё значение, и попросту
ждёт:
my $c = Channel.new;
$c.send(1);
say $c.receive; # 1
say $c.receive; # здесь ждёт — канал открыт, но пустПрограмма зависает на втором .receive, потому что
значение может ещё быть отправлено. Об этой опасности и
предупреждала предыдущая страница: забудьте .close — и
обычное «дождись следующего значения» превратится в ожидание, которое
никогда не кончится.
Итак, два исхода противоположны, и это полезно. Закрытый канал, опустев, отказывает сразу — вы получаете видимое исключение, которое можно перехватить. Открытый канал продолжает ждать — что совершенно правильно, пока производитель ещё работает, но оборачивается безмолвным зависанием, если производитель тихо остановился, не закрыв канал. Закрытие канала как раз и превращает это безмолвное зависание в ясный сигнал о том, что поток закончился.
Практика
Пройдите 1 тест по содержанию этой темы.
Навигация по курсу
← Тест — Закрытие канала | Тест — Чтение после конца →
💪 Или перейдите сразу к упражнениям этого
раздела.