Los humanos somos una especie altamente concurrente, delicada.
primer conocido
La primera impresión del lenguaje Go es que admite la programación concurrente de forma nativa y utiliza rutinas, que son más livianas que los hilos.
La diferencia entre procesos, hilos y corrutinas.
- Un proceso es "una instancia de ejecución de un programa" que actúa como una entidad que asigna recursos del sistema. La creación de procesos debe asignar un espacio de direcciones completo e independiente. El cambio de proceso solo ocurre en modo kernel.
- Subproceso: un subproceso es un flujo de ejecución de un proceso que ejecuta de forma independiente su propio código de programa. Es la unidad más pequeña del flujo de ejecución del programa y la unidad básica de programación y despacho del procesador. Un proceso puede tener uno o más subprocesos.
- Corrutinas: Las corrutinas no son procesos o subprocesos, y su ejecución es más como una subrutina o una llamada de función sin un valor de retorno. Las corrutinas concurrentes se pueden crear a nivel de idioma y luego escribir para administrarlas. Subcontrate este paso para que las corrutinas sean menos costosas de ejecutar al mismo tiempo.
Go implementa la concurrencia más simple
for i := 0; i < 10; i++ {
go func(n int) {
fmt.Println(n)
}(i)
}
复制代码
Práctica del proyecto
Recientemente, un proyecto necesita llamar a varios trabajos al mismo tiempo y esperar a que estos trabajos se completen antes de ejecutarse.
Ejecutar trabajo en serie
Inicialmente, tenemos un método que ejecuta el trabajo y ejecuta todos los trabajos en serie:
func buildJob(name string) {
...
}
buildJob("A")
buildJob("B")
buildJob("C")
复制代码
Ejecutar trabajos en paralelo
Debido a que todos los trabajos se pueden ejecutar simultáneamente, no es necesario esperar a que se complete la ejecución del trabajo anterior antes de continuar con la ejecución de otros trabajos. Podemos usar la palabra clave Go go
para habilitar uno rápidamente goroutine
, a continuación ejecutaremos tres trabajos al mismo tiempo:
go buildJob("A")
go buildJob("B")
go buildJob("C")
复制代码
esperar a que terminen todos los trabajos
Cómo saber si cada trabajo se ha completado, aquí puede usar channel
para comunicarse y usar para select
verificar el resultado de la ejecución:
func buildJob(ch chan error, name string) {
var err error
... // build job
ch <- err // finnaly, send the result into channel
}
func build() error {
jobCount := 3
errCh := make(err chan error, jobCount)
defer close(errCh) // 关闭 channel
go buildJob(errCh, "A")
go buildJob(errCh, "B")
go buildJob(errCh, "C")
for {
select {
case err := <-ch:
if err != nil {
return err
}
}
jobCount--
if jobCount <= 0 {
break
}
}
return nil
}
复制代码
problema encontrado
Cuando el trabajo A falla, el build
método return err
sale y se ejecuta close(errCh)
. Sin embargo, en este momento, es posible que los otros dos trabajos B y C aún no se hayan ejecutado, y los resultados se les enviarán al mismo tiempo errCh
, pero como errCh
se , el programa se cerrará panic: send on closed channel
.
optimizar código
Al enviar datos al canal, puede usar el segundo valor de los datos recibidos para determinar si el canal está cerrado:
func buildJob(ch chan error, name string) {
var err error
... // build job
if _, ok := <-ch; !ok {
return
}
ch <- err // finnaly, send the result into channel
}
func build() error {
jobCount := 3
errCh := make(err chan error, jobCount)
defer close(errCh) // 关闭 channel
go buildJob(errCh, "A")
go buildJob(errCh, "B")
go buildJob(errCh, "C")
for {
select {
case err := <-ch:
if err != nil {
return err
}
}
jobCount--
if jobCount <= 0 {
break
}
}
return nil
}
复制代码
Resumir
Parece que la programación concurrente solo necesita una palabra clave go
para ejecutar una goroutine
, pero en la práctica real, todavía hay problemas que deben abordarse.
Enlace original: k8scat.com/posts/code-…