我遇到了一个奇怪的问题。脚本如下。
package main
import (
"fmt"
"sync"
)
type Data struct {
data []int
}
func main() {
ws := 5
ch := make(chan *Data, ws)
var wg sync.WaitGroup
for i := 0; i < ws; i++ {
wg.Add(1)
go func(wg *sync.WaitGroup, ch chan *Data) {
defer wg.Done()
for {
char, ok := <-ch
if !ok {
return
}
fmt.Printf("Get: %d\n", len(char.data))
}
}(&wg, ch)
}
var d Data
ar := []int{1}
for i := 0; i < ws; i++ {
d.data = []int{}
for j := 0; j < 1000; j++ {
d.data = append(d.data, ar[0])
}
ch <- &d
// time.Sleep(time.Second / 1000) // When this line is moved, a number of data by put and get becomes same.
fmt.Printf("Put: %d\n", len(d.data))
}
close(ch)
wg.Wait()
}
这是运行,预计会有以下结果。 “Put”和“Get”的数据数量相同。
Put: 1000
Get: 1000
Put: 1000
Get: 1000
Put: 1000
Get: 1000
Put: 1000
Get: 1000
Put: 1000
Get: 1000
但是,每次都无法得到这个结果。结果如下。 “Put”和“Get”的数据数量每次都不同。
尝试1
Put: 1000
Get: 1000
Put: 1000
Get: 1000
Put: 1000
Get: 1000
Put: 1000
Get: 1000
Put: 1000
Get: 1000
尝试2
Put: 1000
Get: 1000
Put: 1000
Get: 1000
Put: 1000
Get: 1000
Put: 1000
Get: 16
Put: 1000
Get: 0
尝试3
Get: 1000
Put: 1000
Put: 1000
Get: 1
Put: 1000
Get: 1000
Put: 1000
Get: 1
Put: 1000
Get: 1000
虽然在我的电脑上,“Put”和“Get”的数据数量每次都不同,在play.golang.org,两个数据的数量总是相同的。 https://play.golang.org/p/QFSuZmZk7d为什么?
如果脚本中使用了time.Sleep(time.Second / 1000)
,则两个数据的数量都相同。如果你知道这个问题,请你教我。非常感谢你的时间。
答案 0 :(得分:0)
您观察到的是&#34;数据竞赛&#34;。
的示例当您同时访问同一条数据(其中至少有一条是写入数据)时会发生这种情况。
每次都会引用相同的结构。接下来可能发生的是少数可能性之一:
在你突变它之前在频道的另一边阅读了它(&#34;预期&#34;场景)
你在阅读之前开始改变它。在这种情况下,接收器可以读取任意数量的Data.data
项,从0到1000,具体取决于读取的确切时间。
该问题有多种解决方案:
您可以在每次迭代时创建Data
的新实例。为此,只需在循环体内移动var d Data
声明即可。在这种情况下,每次迭代都会创建一个新结构,因此您可能不会错误地改变前一个结构。
您可以声明Data
的频道(结构,而不是指向结构的指针):chan Data
。在这种情况下,每次将Data
实例发送到通道时都会隐式复制{{1}}实例(因为Go中的所有内容都按值传递,在分配时复制)。
答案 1 :(得分:0)
package main
import (
"fmt"
"sync"
)
/*
信号量的考察,put 之后,必须等待 get 拿到之后才能推出循环
*/
type Data struct {
data []int
}
func main() {
ws := 5
ch := make(chan *Data, ws)
sem := make(chan bool)
var wg sync.WaitGroup
for i := 0; i < ws; i++ {
wg.Add(1)
go func(wg *sync.WaitGroup, ch chan *Data) {
defer wg.Done()
for {
char, ok := <-ch
if !ok {
return
}
fmt.Printf("Get: %d\n", len(char.data))
sem <- true
}
}(&wg, ch)
}
var d Data
ar := []int{1}
// ws = 5
for i := 0; i < ws; i++ {
d.data = []int{}
for j := 0; j < 1000; j++ {
d.data = append(d.data, ar[0])
}
ch <- &d
fmt.Printf("Put: %d\n", len(d.data))
<-sem // 一个信号量,必须等待 get 完成之后才能继续put
}
close(ch)
wg.Wait()
}