2013-03-30 2 views
8

Я пытаюсь сделать некоторые вычисления параллельно. Программа разработана таким образом, что каждый рабочий goroutine отправляет «куски» разрешенной головоломки обратно в контроллер goroutine, который ждет приема и сборки всего, отправленного из рабочих подпрограмм.Как закрыть канал, на который отправляются несколько goroutines?

Что такое idomatic Go для закрытия единственного канала? Я не могу позвонить по каналу в каждом горуте, потому что тогда я мог бы отправить по закрытому каналу. Точно так же нет способа предопределить, какой горутин закончит первым. Является ли sync.WaitGroup необходимым здесь?

ответ

9

Вот пример использования sync.WaitGroup делать то, что вы ищете,

Этот пример принимает lenghty список целых чисел, затем суммирует их все путем передачи ŋ параллельные рабочим равные по размеру кусок входа данные. Его можно запустить на 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

Спасибо, это отлично сработало для того, что мне было нужно. –

+0

Некоторые из этого кода немного ... нечетные. В частности, goroutine с выбором for/single-case-select накапливает результаты и перезаписывает переменную без синхронизации. Некоторые мелкие перестановки и вещи становятся более надежными/понятными: http://play.golang.org/p/5bmlTbdIQa – Dustin

4

Да, это идеальный вариант использования для sync.WaitGroup.

Другой вариант - использовать 1 канал на один канал и один мультиплексор goroutine, который подается от каждого канала в один канал. Но это будет неудобно быстро, поэтому я просто займусь sync.WaitGroup.

Смежные вопросы