Подтвердить что ты не робот

Проверка наличия готового к чтению канала с помощью Go

Как проверить, имеет ли канал значение для чтения?

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

Спасибо!

4b9b3361

Ответ 1

ПРЕДУПРЕЖДЕНИЕ. Это более неточно, см. ответ ниже.

Из документов:

Если выражение получения используется в назначение или инициализацию форма

x, ok = <-ch
x, ok := <-ch
var x, ok = <-ch

операция приема становится неблокирующая. Если операция может continue, логическая переменная ok будет установите значение true и значение, сохраненное в Икс; иначе ok устанавливается в false и x устанавливается на нулевое значение для его типаС >

Ответ 2

Единственная неблокирующая операция, которую я знаю для чтения из канала, находится внутри выбрать блок, имеющий случай по умолчанию:

    select {
    case x, ok := <-ch:
        if ok {
            fmt.Printf("Value %d was read.\n", x)
        } else {
            fmt.Println("Channel closed!")
        }
    default:
        fmt.Println("No value ready, moving on.")
    }

Пожалуйста, попробуйте неблокировать здесь

Примечание о предыдущих ответах: сам оператор-получатель теперь выполняет операцию блокировки, начиная с Go 1.0.3. Изменен spec. Пожалуйста, попробуйте заблокировать здесь (тупик)

Ответ 3

Если вы делаете это часто, то это, вероятно, не отличный дизайн, и вам может быть лучше не создавать другой goroutine, чтобы делать любую работу, которую вы планируете делать, когда нет ничего, что можно было бы читать с канала. Синхронный/блокирующий характер каналов Go упрощает чтение и объяснение кода, в то время как планировщик и дешевые goroutines означает, что асинхронные вызовы не нужны, поскольку ожидания goroutines занимают очень мало ресурсов.

Ответ 4

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

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

Причина в том, что он представляет состояние гонки. Учитывая канал ch, ваш goroutine может видеть, что len (ch) > 0 и заключить, что есть ожидаемое значение. Однако он не может заключить, что он может читать из канала без блокировки - другой goroutine может опорожнить канал между временем проверки len и временем выполнения вашей операции получения.

Для описанной цели используйте select со стандартным случаем, показанным Ripounet.

Ответ 5

К сожалению, предыдущие ответы неверны. spec ясно говорит, что вы можете использовать каналы таким образом, используя функцию len(), но только если вы указали емкость канала - длину буфера для канала при его создании. Если вы пропустили пропускную способность канала при его создании - операции с каналом всегда блокируются.

Ответ 6

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

Итак, не выполняют следующие шаги, чтобы определить, готов ли канал к чтению во время выполнения:

  • определить hchan waitq sudog структуры, как определено здесь, https://golang.org/src/runtime/chan.go
  • используйте "небезопасный" пакет, чтобы передать канал указателю на hchan struct
  • прочитайте поле sendq этой структуры, чтобы получить слушатели.
  • прочитайте сначала sudog и прочитайте оттуда поле msg.
  • передать msg соответствующему типу для каналов с использованием "отражать" и "небезопасно"