我在互联网上发现了许多关于互斥的教程,然后我尝试构建自己的样本。请查看以下代码段。
package main
import (
"fmt"
"sync"
"time"
)
func main() {
thread := new(sync.Mutex)
y := 0
for i := 0; i < 10; i++ {
go func() {
y = i
thread.Lock()
fmt.Println(y)
thread.Unlock()
}()
}
time.Sleep(100000)
}
作为输出我只有10但我的目标是获得1,2,3,4 ...... 10。我怎样才能做到这一点?或者我的样本没有任何意义?
答案 0 :(得分:2)
问题是函数闭包绑定到外部作用域变量i
并且i
在循环期间发生了变化。例程执行时(很可能在循环结束后)i
的值为10。
有两种解决方法,第一种是在每个循环上创建一个新变量:
http://play.golang.org/p/ylTENWeuEl
for i := 0; i < 10; i++ {
y := i
go func() {
thread.Lock()
fmt.Println(y)
thread.Unlock()
}()
}
或将值直接传递给函数闭包:
http://play.golang.org/p/DKd12-VNSk
for i := 0; i < 10; i++ {
go func(value int) {
thread.Lock()
fmt.Println(value)
thread.Unlock()
}(i)
}
答案 1 :(得分:2)
你的例子没有意义。只需写下:
package main
import (
"fmt"
)
func main() {
for i := 0; i < 10; i++ {
fmt.Print(i, " ")
}
fmt.Println()
}
输出:
0 1 2 3 4 5 6 7 8 9
修复程序中的错误后,很容易看出使用goroutines不能提供有序的结果。
package main
import (
"fmt"
"runtime"
"sync"
"time"
)
func main() {
runtime.GOMAXPROCS(runtime.NumCPU() + 2)
thread := new(sync.Mutex)
for i := 0; i < 10; i++ {
y := i
go func() {
thread.Lock()
fmt.Print(y, " ")
thread.Unlock()
}()
}
time.Sleep(time.Second)
fmt.Println()
}
输出:
1 0 5 6 2 7 8 9 3 4
游乐场:
答案 2 :(得分:1)
尝试:
for i := 0; i < 10; i++ {
go func(j int) {
thread.Lock()
fmt.Println(j)
thread.Unlock()
}(i)
}
这是why。
答案 3 :(得分:1)
正如peterSO已经指出的那样,如果你只是想按顺序打印,则不需要并发(Go例程)和互斥量:
for i := 0; i < 10; i++ {
fmt.Println(i)
}
但是,如果你想同时进行一些计算,然后按照所需的顺序打印结果,你可以通过使用一个通道解决它并让主程序按顺序处理打印,或者使用{ {1}}如下例所示:
sync.Cond
<强>输出:强>
package main
import (
"fmt"
"sync"
"time"
)
func main() {
var wg sync.WaitGroup
c := sync.NewCond(new(sync.Mutex))
var printed int
for i := 0; i < 10; i++ {
wg.Add(1)
go func(y int) {
// Do some costly calculation that cakes y*y%10 milliseconds
time.Sleep(time.Duration(y*y%10) * time.Millisecond)
c.L.Lock()
// Wait in a loop til it is this goroutine's turn
for printed != y {
c.Wait()
}
fmt.Printf("%d ", y)
printed++
c.L.Unlock()
// Tell the waiting routines to check if it is their turn
c.Broadcast()
wg.Done()
}(i)
}
wg.Wait()
}
游乐场: http://play.golang.org/p/k7tUfKPRxW
我使用0 1 2 3 4 5 6 7 8 9
代替sync.WaitGroup
来防止主要过早退出。但time.Sleep(time.Second)
解决方案并不需要它。