Ir a puntos de conocimiento (02) -Bloqueo causado por un uso inadecuado del canal

¿Cuál es el resultado de ejecutar el siguiente código?

package main

import (
	"fmt"
)

func main() {
    
    
	c := make(chan string) //	创建一个无缓冲的通道
	c <- "hello world"
	fmt.Println(<-c)
}

La respuesta es: se producirá un punto muerto

fatal error: all goroutines are asleep - deadlock!

La razón es: para un canal sin búfer, el remitente y el receptor deben estar preparados al mismo tiempo para garantizar la recepción del mensaje. El código sobre el remitente y el destinatario están main goroutineadentro, no es posible ejecutar ambos al mismo tiempo, debe ser uno tras otro, lo que también llevó a que el remitente espere hasta que el destinatario, el remitente y el receptor debido a la obstrucción puedan no ser ejecutado Al final, el resultado final es un punto muerto.

Cuando el remitente envía un mensaje al canal, si el receptor no está listo en este momento, el remitente siempre estará bloqueado, esperando que llegue el receptor, si el receptor no ha estado allí, se producirá un interbloqueo.

¿Cómo resolver este problema?

Necesitamos saber que los canales son generalmente aplicables al intercambio de información entre diferentes corrutinas, por lo que para solucionar los problemas anteriores, podemos hacer el remitente y el receptor en diferentes corrutinas.

Ver el código a continuación

func main() {
    
    
	ch := make(chan string) //	创建一个无缓冲的通道

	// 启动一个协程
	go func(c chan string) {
    
    
		c <- "hello world"
	}(ch)

	fmt.Println(<-ch)
}

El resultado es el siguiente:

hello world

Sin embargo, si hay un canal de búfer, no se producirá el problema de interbloqueo anterior.

func main() {
    
    
	c := make(chan string, 1) // 容量为 1 的有缓冲通道
	c <- "hello world"
	fmt.Println(<-c)
}

Los resultados se pueden imprimir normalmente después de la ejecución, por lo que el canal almacenado en búfer no requiere que el remitente y el receptor estén listos al mismo tiempo. Después de que el remitente envía el mensaje al canal, puede ir y el receptor solo necesita el mensaje en el canal cuando llegue. Solo quítalo.

Pero seguimos mirando el siguiente código

func main() {
    
    
	c := make(chan string, 1) // 容量为 1 的有缓冲通道
	c <- "hello"
	c <- "world"
	fmt.Println(<-c)
}

¿Cuál es el resultado de la operación?

fatal error: all goroutines are asleep - deadlock!

¿Por qué hay un interbloqueo si hay un canal de búfer?

La razón es que aquí se crea un canal de búfer con una capacidad de 1 y se envían dos mensajes continuamente en el código. Cuando se envía el primer mensaje, el número de mensajes en el canal es igual a la capacidad, y en este momento , solo puede esperar para enviar El mensaje en el canal solo se puede enviar después de que se elimine. El remitente será bloqueado hasta que se elimine el mensaje en el canal.

Es decir, hay un canal en búfer.Cuando el número de información del canal es igual a la capacidad del canal, el remitente continuará bloqueando hasta que el receptor retire el mensaje y el remitente continuará enviando cuando haya capacidad restante.

Entonces, si el envío se ha enviado y el receptor ha estado esperando para recuperar el mensaje, ¿qué sucederá?

func main() {
    
    
	ch := make(chan string)
	go func() {
    
    
		ch <- "hello"
		ch <- "world"
	}()

	for data := range ch {
    
    
		fmt.Println(data)
	}
}

Resultado de salida:

hello
world
fatal error: all goroutines are asleep - deadlock!

El punto muerto volvió a ocurrir, ¿por qué es esto?

La razón es que el remitente lo ignora después de enviarlo, pero ¿qué? El receptor no sabe si el remitente ha completado la transmisión, por lo que espera una eternidad y finalmente provoca un punto muerto.

¿Cómo resolverlo?

Solo necesitamos decirle al destinatario después de que el remitente haya terminado de enviar que he terminado de enviarlo. Puede irse a casa después de recibir el último mensaje. La nuera y el hijo están esperando que regrese a casa.

¿Cómo decírselo al destinatario? close()Puede ser muy simple de usar fuera del canal.

func main() {
    
    
	ch := make(chan string)
	go func() {
    
    
		ch <- "hello"
		ch <- "world"
		close(ch)   // 发送完毕后关闭通道
	}()

	for data := range ch {
    
    
		fmt.Println(data)
	}
}

Entonces, tenemos que desarrollar todo lo que ha confesado, cada pieza está asegurada, todo tiene un eco de buenos hábitos, retroalimentación oportuna al estado actual.

Supongo que te gusta

Origin blog.csdn.net/wohu1104/article/details/115336793
Recomendado
Clasificación