Ome*_*ter 4 pointers go goroutine channels
我正在尝试使用通道来实现一种工作池。请看下面的代码
https://play.golang.org/p/g7aKxDoP9lf(围棋游乐场)
package main
import (
"fmt"
"time"
)
func main() {
q1 := make(chan int)
fmt.Printf("worker 1\n")
go worker1(q1)
for i := 0; i < 10; i++ {
fmt.Printf("sending: %v\n", i)
q1 <- i
}
time.Sleep(time.Second)
fmt.Printf("\n\nworker 2\n")
q2 := make(chan *int)
go worker2(q2)
for i := 0; i < 10; i++ {
fmt.Printf("sending: %v\n", i)
q2 <- &i
}
time.Sleep(time.Second)
}
func worker1(qTodo <-chan int) {
var curr int
for {
select {
case curr = <-qTodo:
fmt.Printf("got: %v\n", curr)
}
}
}
func worker2(qTodo <-chan *int) {
var curr *int
for {
select {
case curr = <-qTodo:
fmt.Printf("got: %v\n", *curr)
}
}
}
Run Code Online (Sandbox Code Playgroud)
这是一个示例输出
worker 1
sending: 0
got: 0
sending: 1
sending: 2
got: 1
got: 2
sending: 3
sending: 4
got: 3
got: 4
sending: 5
sending: 6
got: 5
got: 6
sending: 7
sending: 8
got: 7
got: 8
sending: 9
got: 9
worker 2
sending: 0
got: 0
sending: 1
sending: 2
got: 2
got: 2
sending: 3
sending: 4
got: 4
got: 4
sending: 5
sending: 6
got: 6
got: 6
sending: 7
sending: 8
got: 8
got: 8
sending: 9
got: 10
Run Code Online (Sandbox Code Playgroud)
似乎在worker2收到指针的时候,原来的变量中的值已经改变了,这反映在打印的值上。
问题是如何避免这种情况?如何解决这个问题?
接收到的指针指向的值不是您所期望的,因为您每次都向它发送一个指向同一变量的指针,因此工作人员会在取消引用该指针时看到该变量具有的任何值。解决此类问题的典型方法是在for循环内复制变量并发送指向该变量的指针。这样,您每次都会发送一个指向不同对象的指针。尝试这个:
for i := 0; i < 10; i++ {
fmt.Printf("sending: %v\n", i)
iCopy := i
q2 <- &iCopy
}
Run Code Online (Sandbox Code Playgroud)
这个问题在Effective Go 的 Channels 部分有介绍。这是一个简短的摘录,变量名称已更改以匹配您的代码:
错误在于在 Go
for循环中,循环变量在每次迭代中都被重用,因此该i变量在所有 goroutine 之间共享。那不是我们想要的。我们需要确保i每个 goroutine 都是唯一的。
它继续描述两种解决方案:
i作为参数传递给 goroutine 中的函数由于您的 goroutine 在您的循环之外启动,因此只有 #2 适用于您的代码。