Закрытие каналов
В этой теме мы рассмотрим несколько решений, позволяющих закрывать каналы, а также разберем практические примеры закрытия и поработаем с кодом.
Как изящно закрыть каналы
Давай рассмотрим некоторые критические замечания по поводу дизайна канала Go и правил каналов:
-
Нет простых и универсальных способов проверить, закрыт ли канал, без изменения статуса канала.
-
Закрытие закрытого канала вызовет панику, поэтому опасно закрывать канал, если доводчики не знают, закрыт канал или нет.
-
Отправка значений в закрытый канал вызовет панику, поэтому опасно отправлять значения в канал, если отправители не знают, закрыт ли канал.
Критика выглядит разумной (на самом деле нет). Да, действительно нет встроенной функции проверки, закрылся канал или нет.
На самом деле существует простой способ проверить, закрыт ли канал, если ты можешь убедиться, что никакие значения не были (и не будут) когда-либо отправлены в канал. Метод был показан в прошлой статье. Здесь для большей согласованности метод снова указан в следующем примере.
Пришло время поработать с кодом!
Это не универсальный способ проверить, закрыт ли канал.
На самом деле, даже если есть простая встроенная функция closed для проверки того, был ли закрыт канал, ее полезность будет очень ограниченной, как и встроенная функция len для проверки текущего количества значений, хранящихся в буфере значений. канала. Причина в том, что статус проверяемого канала мог измениться сразу после возврата из вызова таких функций, так что возвращаемое значение уже не могло отражать последний статус только что проверенного канала. Хотя прекратить отправку значений в канал ch при closed(ch) возврате вызова true можно, закрывать канал или продолжать отправлять значения в канал при closed(ch) возврате вызова небезопасно false.
Принцип закрытия канала
Один общий принцип использования каналов Go — не закрывать канал со стороны получателя и не закрывать канал, если у канала есть несколько одновременных отправителей. Мы должны закрывать канал в горутине отправителя только в том случае, если отправитель является единственным отправителем канала.
Конечно, это не универсальный принцип закрытия каналов. Универсальный принцип — не закрывать (и не отправлять значения) закрытые каналы. Если мы можем гарантировать, что никакие горутины больше не будут закрываться и отправлять значения в незакрытый канал, отличный от nil, тогда горутина может безопасно закрыть канал. Однако предоставление таких гарантий получателем или одним из многих отправителей канала обычно требует больших усилий и часто усложняет код. Наоборот, гораздо проще придерживаться упомянутого выше принципа закрытия канала.