2013-03-30 14 views
8

Sto tentando di eseguire alcuni calcoli in parallelo. Il programma è progettato in modo tale che ogni goroutine di un lavoratore mandi "pezzi" di un puzzle risolto alla goroutine del controllore che attende di ricevere e assemblare tutto ciò che viene inviato dalle routine dei lavoratori.Come si chiude un canale che inviano più goroutine?

Qual è il Go idomatic per chiudere il canale singolo? Non riesco a chiamare da vicino il canale in ogni goroutine perché potrei quindi inviare un canale chiuso. Allo stesso modo, non c'è modo di predeterminare quale goroutine finirà per prima. Un sync.WaitGroup è necessario qui?

risposta

9

Ecco un esempio utilizzando il sync.WaitGroup a fare quello che stai cercando,

questo esempio accetta un elenco lenghty di interi, poi tutti in su riassume consegnando N lavoratori parallele di un pezzo uguale dimensioni dell'ingresso dati. Può essere eseguito su go playground:

package main 

import (
    "fmt" 
    "sync" 
) 

const WorkerCount = 10 

func main() { 
    // Some input data to operate on. 
    // Each worker gets an equal share to work on. 
    data := make([]int, WorkerCount*10) 

    for i := range data { 
     data[i] = i 
    } 

    // Sum all the entries. 
    result := sum(data) 

    fmt.Printf("Sum: %d\n", result) 
} 

// sum adds up the numbers in the given list, by having the operation delegated 
// to workers operating in parallel on sub-slices of the input data. 
func sum(data []int) int { 
    var sum int 

    result := make(chan int) 
    defer close(result) 

    // Accumulate results from workers. 
    go func() { 
     for { 
      select { 
      case value := <-result: 
       sum += value 
      } 
     } 
    }() 

    // The WaitGroup will track completion of all our workers. 
    wg := new(sync.WaitGroup) 
    wg.Add(WorkerCount) 

    // Divide the work up over the number of workers. 
    chunkSize := len(data)/WorkerCount 

    // Spawn workers. 
    for i := 0; i < WorkerCount; i++ { 
     go func(i int) { 
      offset := i * chunkSize 

      worker(result, data[offset:offset+chunkSize]) 
      wg.Done() 
     }(i) 
    } 

    // Wait for all workers to finish, before returning the result. 
    wg.Wait() 

    return sum 
} 

// worker sums up the numbers in the given list. 
func worker(result chan int, data []int) { 
    var sum int 

    for _, v := range data { 
     sum += v 
    } 

    result <- sum 
} 
+0

Grazie, questo ha funzionato perfettamente per ciò di cui avevo bisogno. –

+0

Alcuni di quel codice sono un po '... dispari. In particolare, la goroutine con il/for-single-case-select accumula i risultati e sovrascrive una variabile senza sincronizzazione. Alcuni piccoli riarrangiamenti e cose diventano più affidabili/più facili da capire: http://play.golang.org/p/5bmlTbdIQa – Dustin

4

Sì, questo è un caso perfetto per sync.WaitGroup.

L'altra opzione è quella di utilizzare 1 canale per goroutine e una goroutine di multiplexer che si alimenta da ciascun canale in un singolo canale. Ma questo diventerebbe poco maneggevole velocemente, quindi andrei solo con un sync.WaitGroup.

Problemi correlati