go - viajar - vuelos a noruega
Verificar si un canal tiene un valor listo para leer, usando Go (6)
¿Cómo verifico si un canal tiene un valor para leer?
No quiero bloquear al leer un canal. Quiero ver si tiene un valor. Si tiene uno, lo leeré. Si no tiene uno (todavía), haré otra cosa y volveré a consultar más tarde.
¡Gracias!
Desafortunadamente, las respuestas anteriores son incorrectas. La spec dice claramente que PUEDE usar canales de esta manera usando la función len (), pero solo si especificó la capacidad del canal, la longitud del búfer para un canal mientras lo hace. Si omitió la capacidad de un canal mientras lo hacía, las operaciones del canal siempre están bloqueando.
En la mayoría de los casos, confiar en dicha información es una opción de diseño realmente mala. Ni siquiera decir acerca de cómo está sucio en su implementación.
Por lo tanto, no implemente los siguientes pasos para detectar si el canal está listo para leer en tiempo de ejecución:
- defina las estructuras sudog de hchan waitq tal como se definen aquí: https://golang.org/src/runtime/chan.go
- use el paquete "inseguro" para convertir el canal para apuntar a la estructura hchan
- Lea el campo Sendq de esta estructura para obtener oyentes.
- lee primero el sudog y lee el campo msg desde allí.
- convertir msg al tipo apropiado para los canales usando "reflejar" e "inseguro"
La única operación no bloqueadora que conozco para leer de un canal es dentro de un bloque de selección con un caso predeterminado:
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.")
}
Por favor prueba el no bloqueo aquí.
Nota sobre las respuestas anteriores: el operador de recepción en sí es ahora una operación de bloqueo, a partir de Go 1.0.3. La spec ha sido modificada. Por favor, intente el bloqueo aquí (punto muerto)
No lo hace, al menos no para canales síncronos (sin almacenamiento intermedio). No hay manera de saber si un valor está esperando sin pedirle que tome el valor del canal.
Para los canales en búfer, técnicamente puede usar la función len para hacer lo que describe, pero realmente, realmente no debería. Tu técnica no es válida.
La razón es que representa una condición de raza. Dado el canal ch, su goroutine podría ver que len (ch)> 0 y concluir que hay un valor en espera. No puede concluir, sin embargo, que puede leer desde el canal sin bloquear: otra goroutina puede vaciar el canal entre el momento en que comprueba el len y el momento en que se ejecuta la operación de recepción.
Para el propósito que describió, use select con un caso predeterminado como mostró Ripounet.
Si lo hace a menudo, es probable que no sea un gran diseño y que sea mejor que genere otra goroutina para hacer cualquier trabajo que planee hacer cuando no haya nada que leer del canal. La naturaleza sincrónica / bloqueadora de los canales de Go hace que el código sea más fácil de leer y razonar, mientras que el programador y los goroutines baratos hacen que las llamadas asíncronas sean innecesarias, ya que los goroutines en espera ocupan muy pocos recursos.
ADVERTENCIA : Esto ya no es exacto, vea la respuesta a continuación.
De la documentación:
Si se usa una expresión de recepción en una asignación o inicialización del formulario
x, ok = <-ch x, ok := <-ch var x, ok = <-ch
La operación de recepción se convierte en no bloqueante. Si la operación puede continuar, la variable booleana ok se establecerá en verdadera y el valor se almacenará en x; de lo contrario, ok se establece en false y x se establece en el valor cero para su tipo