web-dev-qa-db-fra.com

Comment utiliser une piscine goroutine

Je souhaite utiliser Go pour télécharger des feuilles de calcul du cours des actions de Yahoo Finance. Je vais faire une demande http pour chaque stock dans sa propre goroutine. J'ai une liste d'environ 2500 symboles, mais au lieu de faire 2500 demandes en parallèle, je préférerais en faire 250 à la fois. En Java, je créerais un pool de threads et réutiliserais les threads au fur et à mesure de leur libération. J'essayais de trouver quelque chose de similaire, un pool goroutine, si vous voulez, mais je n'ai pas pu trouver de ressources. J'apprécierais que quelqu'un puisse me dire comment accomplir la tâche à accomplir ou m'indiquer des ressources pour la même chose. Merci!

23
tldr

Le moyen le plus simple, je suppose, est de créer 250 goroutines et de leur transmettre un canal que vous pouvez utiliser pour passer des liens du goroutine principal aux enfants, en écoutant ce canal.

Lorsque tous les liens sont passés aux goroutines, vous fermez un canal et toutes les goroutines viennent juste de terminer leur travail.

Pour vous protéger du goroutine principal avant que les enfants traitent les données, vous pouvez utiliser sync.WaitGroup.

Voici un code pour illustrer (pas une version de travail finale mais montre le point) que j'ai dit ci-dessus:

func worker(linkChan chan string, wg *sync.WaitGroup) {
   // Decreasing internal counter for wait-group as soon as goroutine finishes
   defer wg.Done()

   for url := range linkChan {
     // Analyze value and do the job here
   }
}

func main() {
    lCh := make(chan string)
    wg := new(sync.WaitGroup)

    // Adding routines to workgroup and running then
    for i := 0; i < 250; i++ {
        wg.Add(1)
        go worker(lCh, wg)
    }

    // Processing all links by spreading them to `free` goroutines
    for _, link := range yourLinksSlice {
        lCh <- link
    }

    // Closing channel (waiting in goroutines won't continue any more)
    close(lCh)

    // Waiting for all goroutines to finish (otherwise they die as main routine dies)
    wg.Wait()
}
45
Rostyslav Dzinko

Vous pouvez utiliser la bibliothèque d'implémentation de pool de threads dans Go à partir de ce repertoire git

Here est le blog de Nice sur l'utilisation des canaux comme pool de threads

Extrait du blog

    var (
 MaxWorker = os.Getenv("MAX_WORKERS")
 MaxQueue  = os.Getenv("MAX_QUEUE")
)

//Job represents the job to be run
type Job struct {
    Payload Payload
}

// A buffered channel that we can send work requests on.
var JobQueue chan Job

// Worker represents the worker that executes the job
type Worker struct {
    WorkerPool  chan chan Job
    JobChannel  chan Job
    quit        chan bool
}

func NewWorker(workerPool chan chan Job) Worker {
    return Worker{
        WorkerPool: workerPool,
        JobChannel: make(chan Job),
        quit:       make(chan bool)}
}

// Start method starts the run loop for the worker, listening for a quit channel in
// case we need to stop it
func (w Worker) Start() {
    go func() {
        for {
            // register the current worker into the worker queue.
            w.WorkerPool <- w.JobChannel

            select {
            case job := <-w.JobChannel:
                // we have received a work request.
                if err := job.Payload.UploadToS3(); err != nil {
                    log.Errorf("Error uploading to S3: %s", err.Error())
                }

            case <-w.quit:
                // we have received a signal to stop
                return
            }
        }
    }()
}

// Stop signals the worker to stop listening for work requests.
func (w Worker) Stop() {
    go func() {
        w.quit <- true
    }()
} 
2
Shettyh

Cet exemple utilise deux canaux, un pour les entrées et un autre pour la sortie. Les travailleurs peuvent évoluer à n’importe quelle taille et chaque goroutine fonctionne dans la file d’entrée et enregistre toutes les sorties dans le canal de sortie. Les commentaires sur les méthodes les plus faciles sont les bienvenus.

package main

import (
    "fmt"
    "sync"
)

var wg sync.WaitGroup

func worker(input chan string, output chan string) {
    defer wg.Done()
    // Consumer: Process items from the input channel and send results to output channel
    for value := range input {
        output <- value + " processed"
    }
}

func main() {
    var jobs = []string{"one", "two", "three", "four", "two", "three", "four", "two", "three", "four", "two", "three", "four", "two", "three", "four", "two"}
    input := make(chan string, len(jobs))
    output := make(chan string, len(jobs))
    workers := 250

    // Increment waitgroup counter and create go routines
    for i := 0; i < workers; i++ {
        wg.Add(1)
        go worker(input, output)
    }

    // Producer: load up input channel with jobs
    for _, job := range jobs {
        input <- job
    }

    // Close input channel since no more jobs are being sent to input channel
    close(input)
    // Wait for all goroutines to finish processing
    wg.Wait()
    // Close output channel since all workers have finished processing
    close(output)

    // Read from output channel
    for result := range output {
        fmt.Println(result)
    }

}
0
OkezieE