Как стать автором
Обновить

Комментарии 11

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

С помощью comma,ok синтаксиса:
x, ok := <-ch

Если канал закрылся, ok будет равен false. Это есть в спецификации, кстати.

В момент, когда читатель обрабатывает сообщение, канал закрывают.
В буферизованном канале часть сообщений пропадет, а писатели паникуют.

Нет, в буферизированном канале ничего не пропадёт. Дефолтное значение возвращается только заблокированным читателям (значит, они читают либо из небуферизированного канала, либо буфер пуст)
Вообще, закрытие канала означает по сути сигнал «в этот канал больше писать ничего нельзя». Всё что есть в буфере — будет вычитано корректно.
А close вообще нужно использовать осторожно и только с полным пониманием зачем и кто его делает (отправитель или получатель, в общем случае close каналу делает отправитель). И, кстати, совершенно легально вообще не закрывать канал. При завершении горутин в скопе которых определен канал, сборщик мусора сам корректно все закроет и почистит. Ну, или при выходе из программы.
Из закрытого буферизированного канала можно достать все данные. Потом пойдет дефолт.
Возможно, стоит добавить, что при чтении нескольких каналов одним оператором select go проходит по ним не последовательно, а в случайном порядке.
Это да, в статье select упоминается только для объяснения, как чтение из канала работает под капотом в случае default-case. Подразумевается, что читатель с самим языком знаком :)
Кстати, тут есть не понятный момент. Пусть у меня есть select, который читает из двух каналов.
Default части нет.
Как это работает? Мы ведь не можем заблокировать горутину на одном из каналов (вдруг сообщение придёт в другой?)
Неужели оно бесконечно проверяет оба канала неблокируя совсем? Вряд ли же.
https://golang.org/ref/spec#Select_statements
собственно в начале проверяются все канала, если есть куда писать, или откуда читать выбирается случайный их них, если нет то горутина добавляется в очереди всех каналов перечисленных в селекте
Здесь должен быть тонкий момент при разблокировки горутины, которая висит на нескольких каналах.
Когда в один из каналов придут данные, нужно каким-то образом одной атомарной операцией убрать горутину из recvq всех каналов, которые она слушала. lock какого-либо канала для этого использовать нельзя.
Интересно, как это делается.
Это происходит тут: https://github.com/golang/go/blob/master/src/runtime/select.go#L454

И в момент срабатывания select-а все каналы лочатся:
https://github.com/golang/go/blob/master/src/runtime/select.go#L324
там по коду они ещё освобождаются когда select паркует горутину (иначе другой код просто не сможет записать в канал) и после вейкапа лочаться опять
если в момент времени после пробуждения и до этого лока, другой канал (не который пробудил селект) попробует сделать это ещё раз это условие не даст этого сделать
спасибо
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Истории