Go 通道中缺少数据
我写了一个小程序来练习go频道Go 通道中缺少数据,go,concurrency,channel,goroutine,Go,Concurrency,Channel,Goroutine,我写了一个小程序来练习go频道 package main import ( "log" "strconv" ) var MaxOutstanding int = 1 var channelSize int = 10 var sem = make(chan int, MaxOutstanding) type Request struct { command string data string } func process(req *Request)
package main
import (
"log"
"strconv"
)
var MaxOutstanding int = 1
var channelSize int = 10
var sem = make(chan int, MaxOutstanding)
type Request struct {
command string
data string
}
func process(req *Request) {
log.Println(req)
}
func serve(reqs chan *Request) {
for req := range reqs {
sem <- 1
go func() {
process(req)
<-sem
}()
}
}
func main() {
reqs := make(chan *Request, channelSize)
for i := 0; i < channelSize; i++ {
req := &Request{"start", strconv.Itoa(i)}
reqs <- req
}
close(reqs)
serve(reqs)
}
因此,&{start 0}未打印。为什么缺少这个?因为在SERVICE中,循环变量用于在单独的goroutine上执行的函数文本中,该函数文本由运行循环的goroutine同时修改:data race。如果存在数据竞争,则行为未定义
如果您复制变量,它将工作:
for req := range reqs {
sem <- 1
req2 := req
go func() {
process(req2)
<-sem
}()
}
试穿一下
另一种可能是将其作为参数传递给匿名函数:
for req := range reqs {
sem <- 1
go func(req *Request) {
process(req)
<-sem
}(req)
}
试一试这个
以下几个相关问题对此进行了详细说明:
正如Zan Lynx所指出的,您的主goroutine不会等待所有启动的goroutine完成,因此您可能看不到所有打印的请求。查看此问题如何等待已启动的goroutine:,因为在服务中,循环变量在单独goroutine上执行的函数文本中使用,该函数文本由运行循环的goroutine:data race同时修改。如果存在数据竞争,则行为未定义
如果您复制变量,它将工作:
for req := range reqs {
sem <- 1
req2 := req
go func() {
process(req2)
<-sem
}()
}
试穿一下
另一种可能是将其作为参数传递给匿名函数:
for req := range reqs {
sem <- 1
go func(req *Request) {
process(req)
<-sem
}(req)
}
试一试这个
以下几个相关问题对此进行了详细说明:
正如Zan Lynx所指出的,您的主goroutine不会等待所有启动的goroutine完成,因此您可能看不到所有打印的请求。查看此问题如何等待已启动的goroutines:这是因为当匿名执行程序时,请求总是从请求{0}移动到请求{1},所以从{start 1}打印
这是因为当匿名执行程序执行时,req总是从请求{0}移动到请求{1},所以从{start 1}打印
你和sem的关系很奇怪。如果你想在一个频道上拥有有限数量的读卡器,那么只需要启动那么多的读卡器。每个读者都会阅读需求。呃,随便了。你的sem和我读过的其他Go代码不一样。无论如何,我会这样写,而不是你必须这样做:@ZanLynx谢谢你的额外建议!你和sem的关系很奇怪。如果你想在一个频道上拥有有限数量的读卡器,那么只需要启动那么多的读卡器。每个读者都会阅读需求。呃,随便了。你的sem和我读过的其他Go代码不一样。无论如何,我会这样写,而不是你必须这样做:@ZanLynx谢谢你的额外建议!我注意到您的代码和原始代码不能执行9,因为它没有等待足够长的时间来完成goroutines。@ZanLynx是的,您是对的,我只关注有问题的问题。我意识到这些错误也在有效的go文章中讨论过。然而,读完这篇文章后,我仍然不明白第二个建议是如何工作的。也就是说,req是一个指针,for循环仍在改变它,这与我的代码中的情况相同。唯一的区别是req作为闭包中的参数传递。您能详细说明一下它是如何工作的吗?@drdot在详细的地方添加了3个相关问题的链接。我注意到您的和原始代码不能执行9,因为它没有等待足够长的时间让goroutines完成。@ZanLynx是的,您是对的,我只是把重点放在问题上。我意识到这些错误也会在有效的围棋文章中讨论。然而,读完这篇文章后,我仍然不明白第二个建议是如何工作的。也就是说,req是一个指针,for循环仍在改变它,这与我的代码中的情况相同。唯一的区别是req作为闭包中的参数传递。你能详细说明一下它是如何工作的吗?@drdot在相关问题中添加了3个链接,其中有详细说明。