Contexto y Cancelación

“Context y Cancelación” en Go: Dominando la gestión de múltiples gorutinas

Introducción

Imagina crear un rastreador web que lanza millones de gorutinas, cada una haciendo una petición HTTP, y luego se bloquea. Necesitas una forma de cerrar todas las gorutinas pendientes cuando el programa principal termina para prevenir fugas de recursos. Aquí es donde entra en juego Context. En este artículo, aprenderás a manejar la cancelación de múltiples gorutinas en Go usando Context y cómo, gracias a su uso, puedes prevenir problemas como las fugas de memoria y de recursos.

Fundamentos Teóricos

El paquete context proporciona funcionalidades para la cancelación de gorutinas y el envío de valores específicos de una solicitud a través del árbol de llamadas de una API.

El uso de context es un patrón común que se ve cuando se trabaja con las entradas/salidas de Go. Esta es la forma recomendada por Go para controlar la cancelación de gorutinas, lo cual es especialmente útil cuando se gestionan muchas gorutinas que realizarán operaciones de bloqueo.

La interfaz context.Context en Go incluye métodos para cancelar contextos, establecer deadlínes, crear contextos que se anidan, y transmitir valores de un lugar a otro.

Implementación paso a paso

Un context en Go se crea de esta manera:

ctx := context.Background()

Para luego crear un context que se pueda cancelar, se usa la función WithCancel:

ctx, cancel := context.WithCancel(ctx)

Donde cancel es una función que, cuando se llame, cancelará el contexto ctx.

Ahora, podemos usar este context cancelable para enviar una señal de cancelación a las gorutinas.

go func(ctx context.Context) {
    select {
    case <-ctx.Done():
        fmt.Println("La gorutina cancelada")
    case <-time.After(3 * time.Second):
        fmt.Println("La gorutina completada")
    }
}(ctx)

Aquí hay un ejemplo completo:

package main

import (
    "context"
    "fmt"
    "time"
)

func main() {
    ctx := context.Background()
    ctx, cancel := context.WithCancel(ctx)
    
    go func(ctx context.Context) {
        select {
        case <-ctx.Done():
            fmt.Println("La gorutina ha sido cancelada")
        case <-time.After(3 * time.Second):
            fmt.Println("La gorutina ha completado exitosamente")
        }
    }(ctx)

    time.Sleep(2 * time.Second)
    cancel() // cancelando la gorutina
    
    time.Sleep(2 * time.Second)
}

Si corres este programa, verás que la gorutina se cancela en 2 segundos, antes de cumplirse los 3 segundos que esperaba la gorutina.

Casos de uso reales

La cancelación de context es muy útil en aplicaciones web y otras aplicaciones concurrentes. Por ejemplo, puedes querer cancelar todas las gorutinas que se ejecutan en segundo plano cuando una solicitud HTTP se cierra.

Otro caso de uso es cuando se tiene un límite de tiempo para terminar todas las gorutinas. Puedes usar context.WithTimeout para cancelar todas las gorutinas después de un período específico de tiempo.

Patrones avanzados

El paquete context también permite crear un context con un límite de tiempo usando la función WithTimeout. También puede crear un context con un plazo determinado usando la función WithDeadline.

El patrón de Errgroup combina Context con el patrón de ‘WaitGroup’ para simplificar la gestión de múltiples gorutinas y proporciona una forma de recoger todos los errores que suceden.

Conclusión y recursos

En este artículo, hemos explorado cómo usar el paquete context en Go para manejar la cancelación de gorutinas. Además, vimos cómo usar context en conjunción con select para esperar la terminación de una gorutina o su cancelación.

Existen muchos otros aspectos de context que puedes explorar. Te recomendamos que leas la documentación oficial del paquete context en Go y experimentes con tu propio código.

Para más ejemplos de código y buenas prácticas, visita Golang Context y Go Concurrency Patterns.