Могут ли подпрограммы Go совместно владеть каналом?

Я понимаю, что обычно, если я хочу получить доступ к переменной вне области видимости из подпрограммы Go, я обязан создать копию, которая будет концептуально принадлежать подпрограмме Go. Это также верно для каналов, или они освобождены?

Effective Go #channels объясняет это словами "может показаться странным писать req := req, но это [так в оригинале] допустимо и идиоматично в Go, чтобы сделать это», ссылаясь на этот пример кода:

var sem = make(chan int, MaxOutstanding)
// (other code, filling sem, defining process(..), etc., omitted)

func Serve(queue chan *Request) {
    for req := range queue {
        <-sem
        req := req // Create new instance of req for the goroutine.
        go func() {
            process(req)
            sem <- 1
        }()
    }
}

Мне удалось почти воспроизвести этот код примера в моем собственном проекте (за исключением того, что я использую chan struct{}, а не chan int для своего семафора, и объявляю его локальным для функции Serve). Глядя на это, я задаюсь вопросом, действительно ли доступ к одному и тому же каналу из нескольких одновременных горутин в порядке или требуется что-то вроде sem := sem.


person pyramids    schedule 09.05.2014    source источник
comment
Этот вопрос похож на некоторые другие - вы тоже можете найти их информативными. Чтение с нескольких каналов одновременно в Golang и несколько горутин, прослушивающих один канал   -  person Rick-777    schedule 14.05.2014


Ответы (2)


Доступ к каналу потокобезопасен, поэтому вам не нужно его блокировать, делать его локальные копии или что-то в этом роде.

person Evan    schedule 09.05.2014

Да, нет проблем с использованием одного и того же канала из нескольких горутин, это вполне нормально.

Причина req := req не в пользу горутины, а вместо этого требуется для предотвращения неожиданного поведения внутри замыкания. Без него каждая итерация цикла будет изменять значение req внутри замыкания, а не каждый раз присваивать ему уникальное значение.

Небольшой пример этого эффекта можно найти здесь: http://play.golang.org/p/ylRQkh2SeC< /а>

person Innominate    schedule 09.05.2014
comment
Спасибо, что нашли время ответить на мой вопрос! Однако: как раз такое состояние гонки (неожиданное поведение), как вы упомянули для req, можно опасаться внутри того, что текущая или будущая реализация chan делает внутри. Если вы ответили на мой вопрос, зависит от интерпретации того же канала, который я считаю неоднозначным в этом контексте. Для иллюстрации: если я передам канал в качестве аргумента функции замыканию, останется ли он тем же каналом? Если да, то вы не ответили на мой вопрос; если нет, то какой это канал? - person pyramids; 10.05.2014
comment
Канал — это просто ценность. Вы можете передать это значение всем, что вам нравится. Он всегда будет ссылаться на один и тот же канал, который может быть прочитан или записан любой горутиной, имеющей к нему доступ. Как правило, именно так вы должны разделять каналы между горутинами, поскольку изменение переменной, содержащей значение канала, может вызвать собственные условия гонки, если ее используют несколько горутин. - person Innominate; 10.05.2014
comment
Я знаю, @twotwotwo. Впрочем, это был не мой вопрос. - person pyramids; 10.05.2014