Compartir tecnología

Idioma Go: canal de programación concurrente (canal dual, canal único) y ejemplos de aplicaciones (productor consumidor, modelo de impresora)

2024-07-12

한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina

Canal

Las gorutinas se ejecutan en el mismo espacio de direcciones, por lo que el acceso a la memoria compartida debe estar sincronizado.Las gorutinas comparten memoria a través de la comunicación, en lugar de compartir memoria.

El canal de tipo de referencia es una implementación específica del modo CSP y se utiliza para la comunicación de múltiples rutinas. Implementa la sincronización internamente para garantizar la seguridad de la concurrencia.

tipo de canal

Al igual que el mapa, el canal también es una referencia a la estructura de datos subyacente creada por make.
Cuando copiamos un canal o lo usamos para pasar parámetros de función, simplemente copiamos una referencia de canal, por lo que la persona que llama y el destinatario harán referencia al mismo objeto de canal. Como otros tipos de referencia, el valor cero del canal es nulo.
Cuando define un canal, también necesita definir el tipo de valores enviados al canal. Los canales se pueden crear usando la función make() incorporada:

make (chan Type)
make (chan Type,capacity)
  • 1
  • 2
  • Cuando capacidad = 0, el canal no tiene búfer y bloquea la lectura y escritura. Cuando capacidad> 0, el canal tiene un caché y no bloquea la escritura hasta que se llenen los elementos de capacidad.
  • Chamnel recibe y envía datos a través del operador <-. La sintaxis para enviar y recibir datos es:
channel<-value   //发送value 到channel
<-channel     //接收并将其丢弃
x:=<-channel   //从 channel 中接收数据,并賦偵给x
x,ok:=<-channel   //功能同上,同时检查通道是否已关闭或者是否为空
  • 1
  • 2
  • 3
  • 4

De forma predeterminada, el canal se bloquea al recibir y enviar datos, a menos que el otro extremo esté listo, lo que simplifica la sincronización de rutinas sin la necesidad de bloqueos explícitos.

lograr

Insertar descripción de la imagen aquí

  • Los tubos se colocan uno delante de la impresión y otro detrás de la impresión.
  • Si Person2 se ejecuta primero y no hay datos en la canalización, se bloqueará.
  • Persona1 se ejecuta y después de imprimir los datos, ingresa los datos en la tubería. Persona2 los detectará y comenzará a imprimir.

Implementar sincronización e interacción de datos a través de canales.

Insertar descripción de la imagen aquí
Insertar descripción de la imagen aquí

canal sin búfer

Un canal sin búfer es un canal que no tiene la capacidad de guardar ningún valor antes de recibirlo.
Este tipo de canal requiere que la rutina de envío y la rutina de recepción estén listas al mismo tiempo para completar las operaciones de envío y recepción. Si dos gorutinas no están listas al mismo tiempo, el canal hará que la gorutina que realiza primero la operación de envío o recepción se bloquee y espere.
Esta interacción de envío y recepción al canal es inherentemente sincrónica. Ninguna operación puede existir independientemente de la otra.
La siguiente figura muestra cómo dos gorutinas pueden compartir un valor utilizando canales sin búfer:
Insertar descripción de la imagen aquí

  • Es decir, el canal en sí no puede almacenar cosas. Si pones algo en uno, puedes sacarlo inmediatamente.
  • En el paso 1, ambas gorutinas llegan al canal, pero ninguna comienza a enviar ni a recibir.
  • En el paso 2, la rutina de la izquierda mete la mano en el canal, lo que simula el acto de enviar datos al canal. En este momento, la gorutina se bloqueará en el canal hasta que se complete el intercambio.
  • En el paso 3, la gorutina de la derecha mete la mano en el canal, lo que simula la recepción de datos del canal. Esta rutina también se bloqueará en el canal hasta que se complete el intercambio.
  • En los pasos 4 y 5, se produce un intercambio y, finalmente, en el paso 6, ambas gorutinas sacan sus manos del canal, lo que simula la liberación de la gorutina bloqueada. Ambas gorutinas ahora pueden hacer otras cosas.

Crear un canal sin búfer

make (chan Type)//等价于make (chan Type,0)
  • 1

Si no se especifica ningún tamaño de búfer, el canal es síncrono y, por lo tanto, se bloquea hasta que el remitente esté listo para enviar y el receptor esté listo para recibir.

Insertar descripción de la imagen aquí

  • ch &lt;-i escribe datos en el canal y la rutina principal no se ejecutará hasta que lo detecte. En este momento, la rutina secundaria también se bloqueará y esperará. Después de que la tubería haya leído los datos, la rutina secundaria continuará. .
  • Sin embargo, println imprime datos después de leer la tubería, por lo que el sistema determina la velocidad de impresión.

canal almacenado en buffer

Un canal almacenado en búfer es un canal que puede almacenar uno o más valores antes de ser recibido.
Este tipo de canal no requiere que la rutina deba completar el envío y la recepción al mismo tiempo. Los canales también tendrán diferentes condiciones que bloquean las acciones de envío y recepción. La acción de recepción solo se bloqueará si no hay ningún valor en el canal a recibir. La acción de envío solo se bloqueará si el canal no tiene un búfer disponible para acomodar el valor que se envía.
Esto conduce a una gran diferencia entre los canales con y sin búfer: los canales sin búfer garantizan que las rutinas de envío y recepción intercambiarán datos al mismo tiempo; los canales con búfer no tienen tal garantía.
Insertar descripción de la imagen aquí

  • En el paso 1, la rutina de la derecha recibe un valor del canal.
  • En el paso 2, la gorutina de la derecha completa la acción de recibir el valor de forma independiente, mientras que la gorutina de la izquierda envía un nuevo valor al canal.
  • En el paso 3, la rutina de la izquierda todavía envía un nuevo valor al canal, mientras que la rutina de la derecha recibe otro valor del canal. Las dos operaciones en este paso no están sincronizadas ni se bloquean entre sí.
  • Finalmente, en el paso 4, se completa todo el envío y la recepción y todavía quedan algunos valores en el canal y algo de espacio para almacenar más valores.

crear

make (chan Type,capacity)
  • 1

Si se proporciona una capacidad de búfer, el canal es asíncrono. Mientras el búfer tenga espacio no utilizado para enviar datos o contenga datos que se puedan recibir, la comunicación continúa sin bloquearse.

lograr

Insertar descripción de la imagen aquí

  • Si se almacenan suficientes tres, se bloqueará y esperará la lectura. Cuando la rutina principal haya leído un dato y haya espacio libre, la subrutina continuará ejecutándose y el orden de impresión posterior no será seguro.
    Insertar descripción de la imagen aquí

cerrar canal

El canal puede usar ok para detectar si el canal todavía está abierto. Si el canal está cerrado, los datos no se leerán.

Insertar descripción de la imagen aquí

  • num ,ok:=<-chPuede detectar si un canal está cerrado.

Aviso

  • No es necesario cerrar los canales con frecuencia como los archivos. Solo cierre el canal cuando realmente no tenga ningún dato para enviar, o si desea finalizar explícitamente el bucle de rango o similar;
  • Después de cerrar el canal, no se pueden enviar más datos al canal (se activa un error de pánico que hace que la recepción devuelva un valor cero inmediatamente):
  • Después de cerrar el canal, puedes continuar recibiendo datos del chamnel:
  • Para canales nulos, se bloquearán tanto el envío como la recepción.
    Insertar descripción de la imagen aquí
  • Puedes usar el rango para atravesar el canal y saltar automáticamente fuera del bucle.
    Insertar descripción de la imagen aquí

canal unidireccional

De forma predeterminada, el canal es de doble pregunta, es decir, puede enviarle y recibir datos.
Sin embargo, a menudo vemos que se pasa un canal como parámetro y se espera que el valor se use en una dirección, ya sea solo para enviar datos o solo para recibir datos. En este momento, podemos especificar la dirección del canal. La declaración de una variable chamel unidireccional es muy sencilla, de la siguiente manera:

var ch1 chan int //ch1双向
var ch2 chan<-float64 //ch2单向,只能用于写float64数据
var ch3 <-chan int  //ch3单向,只能用于读int数据
  • 1
  • 2
  • 3

chan &lt;- significa que los datos ingresan a la tubería y los datos se escriben en la tubería y se envían a la persona que llama.
&lt;-chan indica que los datos provienen de la tubería. Para la persona que llama, se obtienen los datos de la tubería, que por supuesto es la entrada.
Un canal se puede convertir implícitamente en una cola unidireccional, solo recepción o envío, pero un canal unidireccional no se puede convertir en un canal normal;

Insertar descripción de la imagen aquí

Utilizar un único canal para implementar el modelo productor-consumidor.

Insertar descripción de la imagen aquí