2015-12-28 2 views
0

Я столкнулся с проблемой синхронизации при использовании goroutines. Моя программа выводит непредсказуемые результаты. Я проверил документ, а для небуферизованных каналов нет возможности проверить, были ли обработаны все сообщения. Я упростил проблему к этому маленькому демо-коду, который все еще демонстрирует проблему. Ясно, что это не проблема с Golang, а с моим кодом. Очевидно, что я не использую правильный шаблон параллелизма.проблема синхронизации параллелизма golang

Вопрос в том, как это решить. Если возможно, я не хотел бы закрывать канал и не останавливать улей. Думаю, было бы здорово, если бы я мог предположить, что, как только все пчелиные курорты закончатся, этот улей уже сделан (это то, что я пробовал с помощью wg.Wait()).

package main 

import(
    "fmt" 
    "sync" 
    "time" 
) 



func main() { 
    count := int64(0) 
    c := make(chan int64) 
    var wg sync.WaitGroup 

    // bees 
    for i:=0; i<5000;i++{ 
     wg.Add(1) 
     go func(in chan int64) { 
      defer wg.Done() 
      time.Sleep(100) 
      in <- 2 
     }(c) 
    } 

    // hive 
    go func() { 
     for out := range c { 
      count += out 
     } 
    }() 

    wg.Wait() 
    // bang! but why? 
    fmt.Println(count) 
} 

// every now and again the program prints out before it is finished 
// $ go run pattern1.go 
// 10000 
// $ go run pattern1.go 
// 9998 
// $ go run pattern1.go 
// 9998 
// $ go run pattern1.go 
// 10000 
// $ go run pattern1.go 
// 10000 
// $ go run pattern1.go 
// 9998 
+0

У вас есть гонки данных в коде, пожалуйста, запустите ваш код с флагом '-race' (go run/build -race). Это будет печатать информацию о гонках данных по мере их появления. – nussjustin

+0

Вы не можете определить, обрабатывал ли цикл «hive» все значения с 'c', не закрывая' c', или вставляя другой счетчик и примитив синхронизации. Если все goroutines сделаны, то в чем смысл не закрывать канал? – JimB

+1

Флаг -race должен быть выполнен после запуска, но перед именем файла. Все, что после имени файла передается вашему процессу, но -race - это флаг компилятора. – nussjustin

ответ

4

Вы никогда не ждали «улья» петли до конца, так что иногда печатать значение count, прежде чем он будет завершен.

Это проще всего использовать WaitGroup сигнализировать, когда закрыть канал, и блок main на цикл Диапазон:

go func() { 
    wg.Wait() 
    close(c) 
}() 

for out := range c { 
    count += out 
} 

http://play.golang.org/p/jK24dtG2je

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