Go语言中的线程同步

huangapple go评论115阅读模式
英文:

Synchronisation of threads in Go lang

问题

我想更多地了解Go语言中线程同步的工作原理。下面是一个使用done通道进行同步的程序示例:

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
	<-done
	Printf("这是i的值:%d\n", <-i_chan)
}

然而,当我尝试在没有任何同步的情况下运行它时,即使用等待语句而没有通道来指定何时完成,它会打印出错误的i值。

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("这是i的值:%d\n", <-i_chan)
}

如果你延长等待时间,比如1秒钟,它会完成并打印出正确的结果。我大致理解这与两个线程在打印i_chan上的内容之前未完成有关,但我对其工作原理还有些好奇。

英文:

I want to understand a bit more about how synchronisation of threads works in go. Below here I've have a functioning version of my program which uses a done channel for syncronization.

package main

import (
	. &quot;fmt&quot;
	&quot;runtime&quot;
)

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

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

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

However when I try to run it with out any synchronisation. Using a wait statement and no channel to specify when it's done so no synchronisation.

const MAX = 1000000

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

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

It'll print out the wrong value of i. If you extend the wait for let say 1 sec it'll finish and print out the correct statement. I kind of understand that it has something with both thread not being finished before you print what's on the i_chan I'm just a bit curious about how this works.

答案1

得分: 1

请注意,你的第一个例子会发生死锁,因为它从未调用GoRoutine2(原始问题已被编辑)。如果它调用了GoRoutine2,那么期望的i值确实是0

在没有同步的情况下(如此示例),无法保证main()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)
}

更多信息请参见"如何在继续之前等待所有Goroutine执行完毕",其中的规范方法是使用sync包的WaitGroup结构,就像这个可运行的示例中所示。

英文:

Note that your first example would deadlock, since it never calls GoRoutine2 (the OP since edited the question).
If it calls GoRoutine2, then the expected i value is indeed 0.

Without synchronization, (as in this example), there is no guarantee that the main() doesn't exit before the completion of Goroutine1() and Goroutine2().
For a 1000000 loop, a 1 millisecond wait seems enough, but again, no guarantee.

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

see more at "How to Wait for All Goroutines to Finish Executing Before Continuing", where the canonical way is to use the sync package’s WaitGroup structure, as in this runnable example.

huangapple
  • 本文由 发表于 2015年1月23日 08:46:41
  • 转载请务必保留本文链接:https://go.coder-hub.com/28101302.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定