2015-01-23 5 views
-3

Я хочу понять немного больше о том, как синхронизация потоков работает в go. Ниже я имею функциональную версию моей программы, которая использует готовый канал для синхронизации.Синхронизация потоков в Go lang

package main 

import (
    . "fmt" 
    "runtime" 
) 

func Goroutine1(i_chan chan int, done chan bool) { 
    for x := 0; x < 1000000; x++ { 
     i := <-i_chan 
     i++ 
     i_chan <- i 
    } 
    done <- true 
} 
func Goroutine2(i_chan chan int, done chan bool) { 
    for x := 0; x < 1000000; x++ { 
     i := <-i_chan 
     i-- 
     i_chan <- i 
    } 
    done <- true 
} 

func main() { 
    i_chan := make(chan int, 1) 
    done := make(chan bool, 2) 
    i_chan <- 0 

    runtime.GOMAXPROCS(runtime.NumCPU()) 
    go Goroutine1(i_chan, done) 
    go Goroutine2(i_chan) 
    <-done 
    <-done 
    Printf("This is the value of i:%d\n", <-i_chan) 
} 

Однако, когда я пытаюсь запустить его без какой-либо синхронизации. Использование оператора wait и никакого канала для указания, когда это делается, поэтому нет синхронизации.

const MAX = 1000000 

func Goroutine1(i_chan chan int) { 
    for x := 0; x < MAX-23; x++ { 
     i := <-i_chan 
     i++ 
     i_chan <- i 
    } 
} 

func main() { 
    i_chan := make(chan int, 1) 
    i_chan <- 0 
    runtime.GOMAXPROCS(runtime.NumCPU()) 
    go Goroutine1(i_chan) 
    go Goroutine2(i_chan) 
    time.Sleep(100 * time.Millisecond) 
    Printf("This is the value of i:%d\n", <-i_chan) 
} 

Он напечатает неправильное значение i. Если вы продлеваете ожидание, скажем, 1 секунду, он закончит и распечатает правильную инструкцию. Я как бы понимаю, что у него есть что-то, когда оба потока не закончены, прежде чем вы распечатываете то, что находится на i_chan Мне просто немного интересно, как это работает.

+0

Вы не получили сообщение «Goroutine2» в своем первом примере? Где определение «Goroutine2» в вашем втором примере? Вы упоминали что-то о «заявлении ожидания» в своем втором примере - что такое «заявление ожидания» и где оно? –

+1

Примечание: Go не имеет «потоков» в качестве языковой конструкции. Вы имеете в виду «goroutines»? – BraveNewCurrency

+1

Возможный дубликат [Почему fmt.Println внутри goroutine не печатает строку?] (Http://stackoverflow.com/questions/16228887/why-does-fmt-println-inside-a-goroutine-not-print- a-line) – Volker

ответ

1

Обратите внимание, что ваш first example would deadlock, since it never calls GoRoutine2 (ОП с тех пор как редактировал вопрос).
Если it calls GoRoutine2, then the expected i value is indeed 0.

без синхронизации, (как in this example), нет никакой гарантии, что основные() не выходит , прежде чем завершения Goroutine1() и Goroutine2().
Для цикла 1000000, 1 миллисекунда ожидания кажется достаточно, но опять же, нет гарантии.

func main() { 
    i_chan := make(chan int, 1) 
    i_chan <- 0 
    runtime.GOMAXPROCS(runtime.NumCPU()) 
    go Goroutine2(i_chan) 
    go Goroutine1(i_chan) 
    time.Sleep(1 * time.Millisecond) 
    Printf("This is the value of i:%d\n", <-i_chan) 
} 

больше на «How to Wait for All Goroutines to Finish Executing Before Continuing», где канонический способ заключается в использовании sync package’s WaitGroup structure, как в this runnable example.

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