Закрытие канала по сравнению с отправкой, например пустая структура?

У меня есть конвейер с горутинами, соединенными каналами, так что каждая горутина запускает другую, пока все не запустятся. Проще говоря, представьте две горутины A и B, так что, когда A будет завершена, она должна сообщить B, что она может работать.

Он работает нормально, и я попробовал несколько вариантов, так как узнал больше о конвейерах в Go.

В настоящее время у меня есть сигнальный канал

ch := make(chan struct{})
go A(ch)
go B(ch)
...

что B блокирует

func B(ch <-chan struct{}) {
    <-ch
    ...

и A закрывается по завершении

func A(ch chan struct{}) {
    defer close(ch)
    ...
}

Это работает нормально, и я также попытался вместо закрытия отправить пустую структуру struct{} в A().

Есть ли разница между закрытием канала или отправкой пустой структуры? В любом случае дешевле / быстрее / лучше?

Естественно, отправка любого другого типа в канале занимает «некоторое» количество памяти, но как обстоят дела с пустой структурой? Close - это просто часть канала, поэтому она не «отправляется» как таковая, даже если информация передается между горутинами.

Я прекрасно осведомлен о преждевременной оптимизации. Это только для понимания вещей, а не для какой-либо оптимизации.

Может быть, есть идиоматический способ Go сделать это вообще?

Спасибо за любые разъяснения по этому поводу!


person murrekatt    schedule 30.03.2015    source источник


Ответы (2)


закрытие канала означает, что посылов на этом канале больше не будет. Обычно это предпочтительнее, поскольку после этого вы получите панику в случае непреднамеренной отправки или закрытия (ошибка программирования). close также может сигнализировать нескольким получателям, что сообщений больше нет, что вы не можете так легко скоординировать, просто отправив контрольные значения.

Естественно, отправка любого другого типа в канале занимает «некоторое» количество памяти, но как обстоят дела с пустой структурой?

Нет никакой гарантии, что для этого потребуется дополнительная память в небуферизованном канале (это полностью деталь реализации). Отправка блокируется до тех пор, пока прием не будет продолжен.

Close - это просто часть канала, поэтому она не «отправляется» как таковая, даже если информация передается между горутинами.

Здесь нет оптимизации, close - это просто еще один тип сообщения, которое можно отправить в канал.

Каждая конструкция имеет четкое значение, и вы должны использовать соответствующий.

  • Отправьте контрольное значение, если вам нужно сигнализировать одному получателю, и оставьте канал открытым для отправки большего количества значений.

  • Закройте канал, если это последнее сообщение, возможно, сигнализируйте нескольким получателям, и отправка или повторное закрытие будет ошибкой.

person JimB    schedule 30.03.2015
comment
Спасибо за ответ. Я знаю, что означает близкое, и спрашивал о close(ch) против ch <- struct{}{}. У вас есть ссылка, которая близко является сообщением, а не собственностью канала? - person murrekatt; 30.03.2015
comment
@murrekatt: close - это логическое сообщение, специальное значение, которое обещает, что больше не будут отправляться значения. Что вы считаете сообщением? Отправка и закрытие просто манипулируют внутренним состоянием канала, вызывая отправку значения получателям. - person JimB; 30.03.2015
comment
Я заглянул в исходный код Go, чтобы узнать, что делает close, и он устанавливает флаг, указывающий, что канал закрыт. - person murrekatt; 31.03.2015

Вы можете получать из закрытого канала несколькими горутинами, и они никогда не будут блокироваться. Это главное преимущество. Это шаблон один_то_многим.

finish := make(chan struct{}) можно использовать в шаблоне many_to_one, когда многие участники, участвующие в программе, хотят сообщить о выполненных действиях, а посторонний не будет panic.

Дело не в потреблении памяти.

person Uvelichitel    schedule 30.03.2015
comment
@Uvelichtiel, разве вы не использовали бы группу ожидания, чтобы сигнализировать одному о завершении? - person murrekatt; 31.03.2015
comment
@murrekatt Группа ожидания синхронизации раньше всех ожидала. Но вас может заинтересовать только законченный победитель. В этом случае победитель не должен закрывать канал, чтобы посторонние не запаниковали отправкой по закрытому каналу. Вместо этого бегуны должны только сигнализировать рефери, что они сделали, и рефери, в свою очередь, закрывает соревнование. - person Uvelichitel; 31.03.2015