verificar verificación verificacion sirve que para los insignias insignia cuenta como celular canales canal go channel

go - verificación - ¿Cómo verificar un canal está cerrado o no sin leerlo?



verificar canal de youtube 2017 (8)

Bueno, puedes usar la rama default para detectarlo, ya que se seleccionará un canal cerrado, por ejemplo: el siguiente código seleccionará por default , channel , channel , la primera selección no está bloqueada.

func main() { ch := make(chan int) go func() { select { case <-ch: log.Printf("1.channel") default: log.Printf("1.default") } select { case <-ch: log.Printf("2.channel") } close(ch) select { case <-ch: log.Printf("3.channel") default: log.Printf("3.default") } }() time.Sleep(time.Second) ch <- 1 time.Sleep(time.Second) }

Este es un buen ejemplo del modo de trabajadores y controlador en Go escrito por @Jimt, en respuesta a " ¿Hay alguna manera elegante de pausar y reanudar cualquier otro truco en Golang? "

package main import ( "fmt" "runtime" "sync" "time" ) // Possible worker states. const ( Stopped = 0 Paused = 1 Running = 2 ) // Maximum number of workers. const WorkerCount = 1000 func main() { // Launch workers. var wg sync.WaitGroup wg.Add(WorkerCount + 1) workers := make([]chan int, WorkerCount) for i := range workers { workers[i] = make(chan int) go func(i int) { worker(i, workers[i]) wg.Done() }(i) } // Launch controller routine. go func() { controller(workers) wg.Done() }() // Wait for all goroutines to finish. wg.Wait() } func worker(id int, ws <-chan int) { state := Paused // Begin in the paused state. for { select { case state = <-ws: switch state { case Stopped: fmt.Printf("Worker %d: Stopped/n", id) return case Running: fmt.Printf("Worker %d: Running/n", id) case Paused: fmt.Printf("Worker %d: Paused/n", id) } default: // We use runtime.Gosched() to prevent a deadlock in this case. // It will not be needed of work is performed here which yields // to the scheduler. runtime.Gosched() if state == Paused { break } // Do actual work here. } } } // controller handles the current state of all workers. They can be // instructed to be either running, paused or stopped entirely. func controller(workers []chan int) { // Start workers for i := range workers { workers[i] <- Running } // Pause workers. <-time.After(1e9) for i := range workers { workers[i] <- Paused } // Unpause workers. <-time.After(1e9) for i := range workers { workers[i] <- Running } // Shutdown workers. <-time.After(1e9) for i := range workers { close(workers[i]) } }

Pero este código también tiene un problema: si desea eliminar un canal de workers en los workers cuando se cierra worker() , se produce un bloqueo.

Si close(workers[i]) , la próxima vez que el controlador escriba en él causará pánico ya que go no puede escribir en un canal cerrado. Si usa algún mutex para protegerlo, se bloqueará en los workers[i] <- Running porque el worker no está leyendo nada del canal y se bloqueará la escritura, y el mutex causará un bloqueo muerto. También puede dar un buffer más grande al canal como solución alternativa, pero no es lo suficientemente bueno.

Así que creo que la mejor manera de resolver esto es cerrar el canal worker() cuando sale, si el controlador encuentra un canal cerrado, saltará sobre él y no hará nada. Pero no puedo encontrar la forma de verificar que un canal ya esté cerrado o no en esta situación. Si trato de leer el canal en el controlador, el controlador podría estar bloqueado. Así que estoy muy confundido por ahora.

PD: Recuperar el pánico elevado es lo que he intentado, pero cerrará la rutina, lo que generó pánico. En este caso, será un controlador, así que no sirve de nada.

Aún así, creo que es útil para el equipo Go implementar esta función en la próxima versión de Go.


De la documentación:

Un canal puede cerrarse con la función incorporada cerrada. La forma de asignación multivaluada del operador de recepción informa si se envió un valor recibido antes de que se cerrara el canal.

https://golang.org/ref/spec#Receive_operator

El ejemplo de Golang en acción muestra este caso:

// This sample program demonstrates how to use an unbuffered // channel to simulate a game of tennis between two goroutines. package main import ( "fmt" "math/rand" "sync" "time" ) // wg is used to wait for the program to finish. var wg sync.WaitGroup func init() { rand.Seed(time.Now().UnixNano()) } // main is the entry point for all Go programs. func main() { // Create an unbuffered channel. court := make(chan int) // Add a count of two, one for each goroutine. wg.Add(2) // Launch two players. go player("Nadal", court) go player("Djokovic", court) // Start the set. court <- 1 // Wait for the game to finish. wg.Wait() } // player simulates a person playing the game of tennis. func player(name string, court chan int) { // Schedule the call to Done to tell main we are done. defer wg.Done() for { // Wait for the ball to be hit back to us. ball, ok := <-court fmt.Printf("ok %t/n", ok) if !ok { // If the channel was closed we won. fmt.Printf("Player %s Won/n", name) return } // Pick a random number and see if we miss the ball. n := rand.Intn(100) if n%13 == 0 { fmt.Printf("Player %s Missed/n", name) // Close the channel to signal we lost. close(court) return } // Display and then increment the hit count by one. fmt.Printf("Player %s Hit %d/n", name, ball) ball++ // Hit the ball back to the opposing player. court <- ball } }


De una manera hacky se puede hacer para los canales que uno intenta escribir recuperando el pánico elevado. Pero no puede verificar si un canal de lectura está cerrado sin leer de él.

O lo harás

  • finalmente lea el valor "verdadero" de él ( v <- c )
  • lea el valor "verdadero" y el indicador "no cerrado" ( v, ok <- c )
  • lea un valor cero y el indicador ''cerrado'' ( v, ok <- c )
  • se bloqueará en el canal leído para siempre ( v <- c )

Solo el último técnicamente no lee del canal, pero eso es de poca utilidad.


No hay forma de escribir una aplicación segura donde necesite saber si un canal está abierto sin interactuar con él.

La mejor manera de hacer lo que quiere hacer es con dos canales: uno para el trabajo y otro para indicar el deseo de cambiar el estado (así como la finalización de ese cambio de estado si eso es importante).

Los canales son baratos. La semántica de sobrecarga de diseño complejo no lo es.

[además]

<-time.After(1e9)

es una forma realmente confusa y no obvia de escribir

time.Sleep(time.Second)

Mantenga las cosas simples y todos (incluido usted) pueden entenderlos.


Sé que esta respuesta es tan tarde, escribí esta solución, Hacking Go , no es seguridad, puede fallar:

import ( "unsafe" "reflect" ) func isChanClosed(ch interface{}) bool { if reflect.TypeOf(ch).Kind() != reflect.Chan { panic("only channels!") } // get interface value pointer, from cgo_export // typedef struct { void *t; void *v; } GoInterface; // then get channel real pointer cptr := *(*uintptr)(unsafe.Pointer( unsafe.Pointer(uintptr(unsafe.Pointer(&ch)) + unsafe.Sizeof(uint(0))), )) // this function will return true if chan.closed > 0 // see hchan on https://github.com/golang/go/blob/master/src/runtime/chan.go // type hchan struct { // qcount uint // total data in the queue // dataqsiz uint // size of the circular queue // buf unsafe.Pointer // points to an array of dataqsiz elements // elemsize uint16 // closed uint32 // ** cptr += unsafe.Sizeof(uint(0))*2 cptr += unsafe.Sizeof(unsafe.Pointer(uintptr(0))) cptr += unsafe.Sizeof(uint16(0)) return *(*uint32)(unsafe.Pointer(cptr)) > 0 }

https://gist.github.com/youssifsayed/ca0cfcf9dc87905d37a4fee7beb253c2


Si escuchas este canal, siempre puedes descubrir que ese canal estaba cerrado.

case state, opened := <-ws: if !opened { // channel was closed // return or made some final work } switch state { case Stopped:

Pero recuerda, no puedes cerrar un canal dos veces. Esto aumentará el pánico.


Tal vez me falta algo, pero parece que la forma más simple y correcta de manejar esto es enviar "detenido" al canal (que finaliza la rutina de ir), cerrar el canal y establecerlo en cero.

Si cree que necesita verificar un canal cerrado sin leerlo, entonces hay un problema con su diseño. (Tenga en cuenta que hay otros problemas con el código, como el "bucle ocupado" de los trabajadores detenidos).


es más fácil verificar primero si el canal tiene elementos, eso aseguraría que el canal esté vivo.

func isChanClosed(ch chan interface{}) bool { if len(ch) == 0 { select { case _, ok := <-ch: return !ok } } return false }