2013-03-30 11 views
8

Próbuję wykonać pewne obliczenia równolegle. Program jest tak skonstruowany, aby każdy pracownik goroutine wysyłał "kawałki" rozwiązanej łamigłówki do kontrolera goroutine, który czeka na otrzymanie i złożenie wszystkiego, co zostało wysłane z procedur roboczych.Jak mogę zamknąć kanał wysyłany przez wiele goroutinów?

Co to jest idomatic do zamykania pojedynczego kanału? Nie mogę zadzwonić blisko na kanał w każdej goroutine, ponieważ wtedy mógłbym wysłać zamknięty kanał. Podobnie, nie ma sposobu, aby z góry określić, który gorynt będzie kończył jako pierwszy. Czy konieczna jest tutaj synchronizacja.WaitGroup?

Odpowiedz

9

Oto przykład przy użyciu sync.WaitGroup robić to, czego szukasz,

Ten przykład akceptuje lenghty listę liczb całkowitych, a następnie sumuje je wszystkie poprzez przekazanie do szumu w równoległe pracownikom równe wielkości kawałek od wejścia dane. Można go uruchomić na: 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

Dziękuję, to działało idealnie na to, czego potrzebowałem. –

+0

Niektóre z tych kodów są trochę ... dziwne. W szczególności, goroutine z wyborem for/single-case gromadzi wyniki i nadpisuje zmienną bez synchronizacji. Niektóre drobne rearanżacje i rzeczy stają się bardziej niezawodne/łatwiejsze do zrozumienia: http://play.golang.org/p/5bmlTbdIQa – Dustin

4

Tak, jest to idealne rozwiązanie do synchronizacji.WaitGroup.

Inną opcją jest użycie 1 kanału na goroutine i jednego goroutine multipleksera, który zasila z każdego kanału w jeden kanał. Ale stanie się to nieporęcznie szybko, więc po prostu pójdę z sync.WaitGroup.

Powiązane problemy