2014-09-16 4 views
2

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

Я создал два примера Fan-В функции (от Go Concurrency Patterns talk)

The first one:

select { 
case value := <-g1: 
    c <- value 
case value := <-g2: 
    c <- value 
} 

отпечатки от каждого канала, как ожидается (каждый канал сохраняет свой собственный счетчик):

Bob : 0 
Alice: 0 
Bob : 1 
Alice: 1 
Bob : 2 
Alice: 2 
Alice: 3 
Alice: 4 
Bob : 3 
Alice: 5 

The second one:

select { 
case c <- <-g1: 
case c <- <-g2: 
} 

Это случайный выбор канала и отбрасывая другую свое значение:

Bob : 0 
Alice: 1 
Alice: 2 
Alice: 3 
Bob : 4 
Alice: 5 
Bob : 6 
Alice: 7 
Alice: 8 
Bob : 9 

Update: при написании этого вопроса, я думал, что второй selectwas equal to:

var v string 
select { 
case v = <-g1: 
case v = <-g2: 
    c <- v 
} 

Но я был неправильно, потому что он всегда печатает со второго канала ( , как и ожидалось от оператора типа switch , потому что в выборе нет провала заявления):

Bob : 0 
Bob : 1 
Bob : 2 
Bob : 3 
Bob : 4 
Bob : 5 
Bob : 6 
Bob : 7 
Bob : 8 
Bob : 9 

Понимает ли кто-то, почему мой второй пример создает последовательность?

Спасибо,

+0

Я ... на самом деле не уверен, что там происходит, но я скажу вам, что ваш третий пример не работает, потому что нет автоматического провала (и нет провала в select statement, period). – andlabs

+0

@andlabs, вы правы, спасибо, отредактируйте вопрос – rvignacio

ответ

4

Ваш второй оператор выбора интерпретируется как:

v1 := <-g1 
v2 := <-g2 
select { 
case c <- v1: 
case c <- v2: 
} 

As described in the language spec, ОРЗ каждого отправить оператор будет оцениваться фронт, когда выполняется оператор:

Выполнение «выберите» выдается в несколько этапов:

  1. Для всех случаев в инструкции операнды канала операции приема и каналы и правые выражения операторов отправки вычисляются ровно один раз в порядке источника при вводе оператора «select». Результатом является набор каналов для приема или отправки и соответствующие значения для отправки. Любые побочные эффекты в этой оценке будут происходить независимо от того, какая из них (если таковая имеется) для выполнения операции связи. Выражения в левой части RecvStmt с коротким объявлением или присваиванием переменной еще не оценены.
  2. Если одно или несколько сообщений могут продолжаться, один, который может продолжить, выбирается с помощью равномерного псевдослучайного выбора. В противном случае, если есть случай по умолчанию, этот случай выбран. Если нет случая по умолчанию, оператор «select» блокируется до тех пор, пока по крайней мере одно из сообщений не поступит.
  3. ...

Так как на стадии (1), как <-g1 и <-g2 будут оценены, принимая значения от каждого канала. Это может блокироваться, если еще ничего не получить.

В (2) мы ожидаем, пока c будет готов отправить значение, а затем случайным образом выбрать ветвь оператора select для выполнения: поскольку они оба ждут на одном канале, они готовы к продолжению.

Это объясняет поведение, которое вы видели, когда значения отбрасываются, и вы получили недетерминированное поведение, в котором значение было отправлено на c.

Если вы хотите подождать g1 и g2, вам нужно будет использовать первую форму для вашего заявления, как вы обнаружили.

+0

Спасибо, я думаю, я это понимаю. Одна вещь, которая меня озадачивает, заключается в том, что она ждет, пока оба канала будут готовы отправить. [См. Этот последний пример] (http://play.golang.org/p/3m67DMgRXB), Алиса готова, пока Боб имеет задержку перед отправкой значения, но вместо того, чтобы выполнять первый «случай», всегда выбирает 'select' ждет задержки в Бобе (так что эта нотация может создавать серьезные проблемы с производительностью, я не понимаю, почему она не указана как частный случай = P) – rvignacio

+0

Как я уже упоминал в своем ответе, фактическая работа оператора select не выполняется до тех пор, пока не будет оценена RHS каждой ветви инструкции. Значения должны быть получены как от 'g1', так и от' g2' до того, как будет принято решение о том, чтобы отправить 'c'. Программа не ожидает отдельного ожидания при каждой операции отправки или получения, которая может быть частью выражений. –

1

Согласно [http://golang.org/ref/spec] The Go Programming Language Specification

for { // send random sequence of bits to c 
    select { 
    case c <- 0: // note: no statement, no fallthrough, no folding of cases 
    case c <- 1: 
    } 
} 

Он будет генерировать 0 или 1 случайным образом.

Для второго exaple

select { 
case c <- <-g1: 
case c <- <-g2: 
} 

когда g1 имеет Bob : 0 и g2 имеет Alice: 0, либо c <- <-g1 или c <- <-g2 будет выполняться, но только одна воля.

Это объясняет, почему у вас есть последовательность 0 1 2 3 4 5 6 7 8 9 но не 0 0 1 1 2 2 3 3 4 4

И это также сказать:

in source order, upon entering the "select" statement. The result is a set of channels to receive from or send to, and the corresponding values to send.

По моему пониманию, даже если c <- <-g1 выполнит, Alice: 0 также выскочит из g2. Поэтому каждый раз, когда у вас есть Bob : i и Alice: i, будет распечатан только один.

Смежные вопросы