Frage

I am attempting to do some computation in parallel. The program is designed so that each worker goroutine sends "pieces" of a solved puzzle back to the controller goroutine that waits to receive and assembles everything sent from the worker routines.

What is the idomatic Go for closing the single channel? I cannot call close on the channel in each goroutine because then I could possibly send on a closed channel. Likewise, there is no way to predetermine which goroutine will finish first. Is a sync.WaitGroup necessary here?

War es hilfreich?

Lösung

Here is an example using the sync.WaitGroup to do what you are looking for,

This example accepts a lenghty list of integers, then sums them all up by handing N parallel workers an equal-sized chunk of the input data. It can be run on 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
}

Andere Tipps

Yes, This is a perfect use case for sync.WaitGroup.

Your other option is to use 1 channel per goroutine and one multiplexer goroutine that feeds from each channel into a single channel. But that would get unwieldy fast so I'd just go with a sync.WaitGroup.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top