Показаны сообщения с ярлыком select утверждения (select statements) в Go. Показать все сообщения
Показаны сообщения с ярлыком select утверждения (select statements) в Go. Показать все сообщения

вторник, 17 марта 2020 г.

Select ожидает по группе каналов

Оператор select ожидает нескольких операций отправки или получения одновременно.

Оператор блокируется целиком, пока одна из операций не станет разблокированной.

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

// блокируется, пока не появятся данные, 
// доступные на ch1 или ch2
select {
case <-ch1:
    fmt.Println("Получено из ch1")
case <-ch2:
    fmt.Println("Получено из ch2")
}

Операции отправки и получения по nil каналу блокируется навсегда. Это можно использовать для отключения канала в операторе select:

ch1 = nil // отключает этот канал
select {
case <-ch1:
    fmt.Println("Получено из ch1") // не произойдет
case <-ch2:
    fmt.Println("Получено из ch2")
}

default случай

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

// никогда не блокирует
select {
case x := <-ch:
    fmt.Println("Получено", x)
default:
    fmt.Println("Нет ничего доступного")
}

Примеры


Бесконечная случайная двоичная последовательность

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

rand := make(chan int)
for {
    select {
    case rand <- 0: // нет оператора
    case rand <- 1:
    }
}

Операция блокировки с тайм-аутом

Функция time.After является частью стандартной библиотеки; она ожидает истечения заданного времени и затем отправляет текущее время по возвращаемому каналу.

select {
case news := <-AFP:
    fmt.Println(news)
case <-time.After(time.Minute):
    fmt.Println("Время вышло: Нет новостей в течение минуты")
}

Утверждение, которое блокирует навсегда

Оператор select блокируется до тех пор, пока не будет продолжен хотя бы один из его случаев. При нулевых случаях это никогда не произойдет.

select {}

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


Читайте также:


Купить gopher

пятница, 21 июня 2019 г.

Спецификация Go: select утверждения (select statements)

Утверждение "select" выбирает, какой из набора возможных операций отправки или получения будет продолжен. Это похоже на утверждние "switch", но со всеми случаями (cases), относящимися к операциям связи.

SelectStmt = "select" "{" { CommClause } "}" .
CommClause = CommCase ":" StatementList .
CommCase   = "case" ( SendStmt | RecvStmt ) | "default" .
RecvStmt   = [ ExpressionList "=" | IdentifierList ":=" ] RecvExpr .
RecvExpr   = Expression .

Случай (case) с RecvStmt может присвоить результат RecvExpr одной или двум переменным, которые могут быть объявлены с помощью краткого объявления переменных. RecvExpr должен быть (возможно заключенной в скобки) операцией приема. Может быть не более одного случая по умолчанию, и он может появиться в любом месте списка случаев (cases).

Исполнение утверждения "select" происходит в несколько этапов:

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

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

var a []int
var c, c1, c2, c3, c4 chan int
var i1, i2 int
select {
case i1 = <-c1:
  print("received ", i1, " from c1\n")
case c2 <- i2:
  print("sent ", i2, " to c2\n")
case i3, ok := (<-c3):  // то же самое что и: i3, ok := <-c3
  if ok {
    print("received ", i3, " from c3\n")
  } else {
    print("c3 is closed\n")
  }
case a[f()] = <-c4:
  // то же самое что и:
  // case t := <-c4
  //  a[f()] = t
default:
  print("no communication\n")
}

for {  // отправляет случайную последовательность битов в c
  select {
  case c <- 0:  // примечание: нет утверждения, нет fallthrough ("провала" в следующий случай), нет сворачивания случаев
  case c <- 1:
  }
}

select {}  // блокируется навсегда


Читайте также: