Проверка, имеет ли канал готовое к чтению значение, используя Go - PullRequest
27 голосов
/ 03 августа 2010

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

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

Спасибо!

Ответы [ 6 ]

78 голосов
/ 30 декабря 2012

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

    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 был изменен. Пожалуйста попробуйте блокировку здесь (тупик)

7 голосов
/ 02 января 2013

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

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

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

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

7 голосов
/ 27 августа 2010

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

5 голосов
/ 10 марта 2016

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

5 голосов
/ 03 августа 2010

ПРЕДУПРЕЖДЕНИЕ : Это больше не является точным, см. Ответ ниже.

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

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

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

операция получения становится неблокирующая. Если операция может продолжить, логическая переменная ок будет быть установленным в true и значение сохранено в Икс; в противном случае ОК устанавливается на ложь и х устанавливается в нулевое значение для его типа

0 голосов
/ 28 ноября 2017

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

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

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