Concurrency en Golang Go mediante Workers

El lenguaje de programación GO es particularmente amigable para desarrollar programas con concurrencia, es decir, poder “lanzar”
tasks simultáneamente en forma asincrónica para que la computadora se haga cargo de ellos y así reducir tiempos.

Un método sencillo es fire and forget, es decir, lanzar varios tasks y al final esperar a la terminación de los mismos antes de salir del programa.

El método más útil resulta ser el lanzar simultáneamente varios procesos idénticos que resuelven porciones del problema e ir agrupando los resultados, de esta forma, para un problema largo o complejo, se tienen varios workers que hacen más veloz la resolución.

Así, se definen 10 workers, se los lanza con la sentencia go, los cuales tienen como parámetro un identificador, el waitgroup que sirve para que el worker avise cuando ha terminado decrementando el contador de worker activos, un canal de ingreso de datos y uno de resultado.

Al worker le entra un trabajo en el canal jobChannel el cual está esperando mediante el loop, ejecuta la función doSomething y devuelve un resultado al canal de resultChannel.


package main

import (
    "fmt"
    "sync"
    "time"
)

type Job struct {
    Id int
}

type JobResult struct {
    Output string
}

func worker(id int, wg *sync.WaitGroup, jobChannel <-chan Job, resultChannel chan JobResult) {
    defer wg.Done()
    for job := range jobChannel {
        resultChannel <- doSomething(id, job)
    }
}

func main() {
    start := time.Now()  // Inicializa una variable donde guardar el tiempo
    var jobs []Job
    for i := 0; i < 100; i++ {
        jobs = append(jobs, Job{Id: i})
    }

    const NumberOfWorkers = 10
    var wg sync.WaitGroup

    wg.Add(NumberOfWorkers)  jobChannel := make(chan Job)
    jobResultChannel := make(chan JobResult, len(jobs))

    // Lanza los workers
    for i := 0; i < NumberOfWorkers; i++ {
        go worker(i, &wg, jobChannel, jobResultChannel)
    }

    // Envía trabajo a los worker
    for _, job := range jobs {
        jobChannel <- job
    }


    // Una vez enviado los trabajos, se cierra el canal   close(jobChannel)
    wg.Wait()
    close(jobResultChannel)

    var jobResults []JobResult
    // Llegan resultados de los workers
    // El loop, al igual que en los workers, levanta un valor 
    // siempre que haya uno y mientras el canal esté abierto.
    for result := range jobResultChannel {
        jobResults = append(jobResults, result)
    }

    fmt.Println(jobResults)
    fmt.Printf("Took %s", time.Since(start))
}

func doSomething(workerId int, job Job) JobResult {
    fmt.Printf("Worker #%d Running job #%d\n", workerId, job.Id)
    time.Sleep(500 * time.Millisecond)
    return JobResult{Output: "Success"}
}

Go Playground

fuente

Check Also

Support Vector Machine Learning – SVM

El algoritmo SVM (Support Vector Machine) es un método de aprendizaje supervisado utilizado para la …

Leave a Reply

Your email address will not be published. Required fields are marked *