2013-08-16 8 views
21

Ich möchte Go verwenden, um Aktienkurs-Tabellen von Yahoo Finance herunterzuladen. Ich werde eine HTTP-Anfrage für jeden Bestand in seiner eigenen Goroutine machen. Ich habe eine Liste von ungefähr 2500 Symbolen, aber anstatt 2500 Anfragen parallel zu machen, würde ich lieber 250 auf einmal machen. In Java würde ich einen Thread-Pool erstellen und Threads wiederverwenden, wenn sie frei werden. Ich habe versucht, etwas Ähnliches zu finden, einen Goroutine-Pool, wenn du willst, aber ich konnte keine Ressourcen finden. Ich würde mich freuen, wenn mir jemand sagen kann, wie ich die Aufgabe erledigen soll oder auf Ressourcen für das gleiche hinweisen soll. Vielen Dank!Wie man einen goroutin Pool verwendet

+0

Brauchen Sie diese Gououtines in einem Pool? Sie behandeln sie wie Ressourcen, die Sie erstellen und wiederverwenden. Oder, würden Sie eine einfachere Lösung in Erwägung ziehen, bei der die Göroutines wegwerfbar sind, aber Sie nur kontrollieren, wie viele von ihnen gleichzeitig laufen? – atedja

Antwort

41

Der einfachste Weg, ich nehme an, ist, 250 goroutines zu schaffen und ihnen einen Kanal zu übergeben, den Sie verwenden können, um Verbindungen von der Hauptgoroutine zu den Kindern zu führen, diesen Kanal hörend.

Wenn alle Links an goroutines übergeben werden, schließen Sie einen Kanal und alle goroutines beenden ihre Aufträge.

Um sich von der Hauptgoroutine zu sichern, bevor Kinder Daten verarbeiten, können Sie sync.WaitGroup verwenden.

Hier einige Code zu veranschaulichen (nicht um eine endgültige Arbeitsversion, sondern zeigt den Punkt), dass ich sagte oben:

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() 
} 
+3

Hier ist ein kleiner Test dieses Codes in Aktion: http://play.golang.org/p/fruJiGBWjn – Druska

1

Sie den Thread-Pool Implementierung Bibliothek in Go von diesem git repo

verwenden können Here ist der schöne Blog darüber, wie die Kanäle als Thread-Pool verwenden

Snippet aus dem 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 
    }() 
} 
Verwandte Themen