Гарантируется, что передача сообщений по каналам в go не блокируется? - PullRequest
8 голосов
/ 17 июля 2011

Чтобы оценить, является ли go возможным вариантом для аудио / видео приложений, я хотел бы знать, удовлетворяет ли передача сообщений в go любым неблокирующим гарантиям прогресса (будь то отсутствие препятствий, отсутствие блокировок или ожидание)).В частности, актуальны следующие сценарии:

Один потребитель-одиночный производитель:

Два потока взаимодействуют с использованием общего канала.Поток A выполняет только асинхронные передачи, поток B выполняет только асинхронные приемы.Предположим, что планировщик ОС решает прервать поток A в «наихудший возможный момент» на неопределенное время.Гарантирован ли поток B завершить операцию приема за ограниченное число циклов ЦП или существует (теоретическая) вероятность того, что поток A может перевести канал в состояние, когда поток B должен ждать, пока ОС возобновит поток A?

Несколько производителей:

Несколько потоков A1, A2, A3, ... взаимодействуют с одним или несколькими другими потоками, используя общий канал.Потоки Ai выполняют только асинхронные передачи.Предположим, что A2, A3, ... приостановлены планировщиком ОС в «наихудший возможный момент» на неопределенное время.Поток A1 по-прежнему гарантированно завершит операцию отправки за ограниченное число циклов ЦП?Предположим далее, что каждый поток хочет выполнить только одну отправку.Если программа выполняется достаточно долго (с «злонамеренным» планировщиком, который потенциально останавливает некоторые потоки или прерывает и возобновляет потоки в «худший возможный момент»), гарантируется ли хотя бы одна передача успешно?

Яздесь интересуются не столько типичные сценарии, сколько гарантии наихудшего случая.См. Алгоритм неблокирования (Википедия) для получения дополнительной информации об алгоритмах без препятствий, блокировок и ожидания.

Ответы [ 4 ]

9 голосов
/ 18 июля 2011

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

select {
case ch <- msg:
default:
}

(Получение очень похоже; просто замените регистр).

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

4 голосов
/ 16 апреля 2012

Модель памяти Go не требует, чтобы отправка и получение были неблокирующими, а текущая среда выполнения реализация блокирует канал для send и recv. Это означает, например, что можно прогнать отправляющую или получающую подпрограмму go, если планировщик ОС прерывает другой поток, выполняющий другую подпрограмму go, которая пытается отправить или получить по тому же каналу, пока он уже получил блокировку канала .

Так что ответ, к сожалению, нет : (

(если кто-то не переопределит части среды выполнения с использованием неблокирующих алгоритмов).

1 голос
/ 18 июля 2011

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

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

Обратите внимание, что кооперативный характер goroutines дает вам некоторый контроль над выполнением планирования, то есть процедуры никогда не прерываются. Пока вы не уступите, вы сохраните контроль над потоком.

Что касается поведения блокировки, см. Спецификация языка :

Емкость, в количестве элементов, устанавливает размер буфера в канале. Если емкость больше нуля, канал является асинхронным: операции связи выполняются без блокировки, если буфер не заполнен (отправляет) или не пуст (получает), а элементы принимаются в порядке их отправки. Если емкость равна нулю или отсутствует, обмен данными будет успешным только тогда, когда отправитель и получатель готовы.

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

0 голосов
/ 20 июля 2011

Городунам не принадлежат каналы или значения, отправленные по ним.Таким образом, состояние выполнения программы, которая отправила / отправляет значения по каналу, не влияет на способность других программ отправлять или получать значения по этому каналу, если только буфер канала не заполнен, и в этом случае все отправки блокируются.пока соответствующий прием не произойдет, или буфер не будет пуст, в этом случае все приемы будут блокироваться, пока не будет соответствующая отправка.

Поскольку подпрограммы используют совместное планирование (они должны уступать планировщику либо через каналОперация, системный вызов или явный вызов runtime.Gosched()) не позволяют прерывать выполнение процедуры в «наихудшее возможное время».Для goroutine возможно никогда не дать, в этом случае, это может связать нить на неопределенный срок.Если у вас есть только один поток выполнения, то другие ваши подпрограммы никогда не будут запланированы.Возможно, но статистически маловероятно, чтобы горутин просто никогда не был запланирован.Однако, если все процедуры, кроме одной, заблокированы при отправке или получении, то оставшаяся процедура должна быть запланирована.

Возможно получить тупик.Если у меня выполняется две подпрограммы:

func Goroutine(ch1, ch2 chan int) {
   i := <-ch1
   ch2 <- i
}
...
ch1, ch2 := make(chan int), make(chan int)
go Goroutine(ch1, ch2)
go Goroutine(ch2, ch1)

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

...