Go 通过通道发送的值不视为已接收
下面的代码启动了一些工作人员。每个worker通过一个通道接收一个值,该通道添加到一个映射中,其中键是worker ID,值是接收到的数字。最后,当我添加所有接收到的值时,我应该得到一个预期结果(在本例中为55,因为这是从1..10添加时得到的结果)。在大多数情况下,我没有看到预期的产出。我做错了什么?我不想通过增加睡眠来解决这个问题。我希望以编程方式确定问题并修复它Go 通过通道发送的值不视为已接收,go,channel,goroutine,Go,Channel,Goroutine,下面的代码启动了一些工作人员。每个worker通过一个通道接收一个值,该通道添加到一个映射中,其中键是worker ID,值是接收到的数字。最后,当我添加所有接收到的值时,我应该得到一个预期结果(在本例中为55,因为这是从1..10添加时得到的结果)。在大多数情况下,我没有看到预期的产出。我做错了什么?我不想通过增加睡眠来解决这个问题。我希望以编程方式确定问题并修复它 type counter struct { value int count int } var data map[st
type counter struct {
value int
count int
}
var data map[string]counter
var lock sync.Mutex
func adder(wid string, n int) {
defer lock.Unlock()
lock.Lock()
d := data[wid]
d.count++
d.value += n
data[wid] = d
return
}
func main() {
fmt.Println(os.Getpid())
data = make(map[string]counter)
c := make(chan int)
for w := 1; w <= 3; w++ { //starting 3 workers here
go func(wid string) {
data[wid] = counter{}
for {
v, k := <-c
if !k {
continue
}
adder(wid, v)
}
}(strconv.Itoa(w)) // worker is given an ID
}
time.Sleep(1 * time.Second) // If this is not added, only one goroutine is recorded.
for i := 1; i <= 10; i++ {
c <- i
}
close(c)
total := 0
for i, v := range data {
fmt.Println(i, v)
total += v.value
}
fmt.Println(total)
}
类型计数器结构{
值int
计数整数
}
var数据映射[字符串]计数器
var lock sync.Mutex
func加法器(wid字符串,n int){
延迟锁定。解锁()
lock.lock()
d:=数据[wid]
d、 计数++
d、 值+=n
数据[wid]=d
回来
}
func main(){
fmt.Println(os.Getpid())
数据=生成(映射[字符串]计数器)
c:=制造(成交量)
对于w:=1;w您的代码有两个重要的种族:
data[wid]=计数器{}
的初始化与可能正在读取和重写数据的其他goroutine不同步
- worker goroutine在完成修改
数据
时不会发出信号,这意味着您的主goroutine可能会在完成写入之前读取数据
您还有一个奇怪的构造:
for {
v, k := <-c
if !k {
continue
}
adder(wid, v)
}
(这很容易改进,例如,wg
没有理由全球化。)好吧,我喜欢@torek的答案,但我想发布这个答案,因为它包含了一系列改进:
减少锁的使用(对于这样简单的任务,避免使用锁。如果您对其进行基准测试,您会注意到一个很好的区别,因为我的代码只使用锁numworkers
次)
改进变量的命名
删除全局变量的使用(全局变量的使用应始终尽可能少)
下面的代码使用numWorker
生成的goroutines将一个数字从minWork
添加到maxWork
主程序包
进口(
“fmt”
“同步”
)
常数(
bufferSize=1//numChan的缓冲区
numworkers=3//进行加法的工人数
minWork=1//来自[minWork]的总和(含)
maxWork=10000000//总计达到[maxWork](含)
)
//工人统计
类型工作结构{
workCount int//工人工作的次数
workDone int//完成的工作量;添加的数字
}
//workerMap保存一个或多个worker的映射
类型workerMap结构{
mu sync.Mutex//保护m以实现安全的并发r/w
m map[int]worker//map用于保存worker id到worker映射
}
func main(){
变量(
TotalWorkOne int//完成的总工时
wm workerMap//workerMap
wg sync.WaitGroup//WaitGroup
numChan=make(chan int,bufferSize)//用于NUM的通道
)
wm.m=make(映射[int]工作者,numworkers)
对于wid:=0;widpackage main
import (
"fmt"
// "os"
"strconv"
"sync"
// "time"
)
type counter struct {
value int
count int
}
var data map[string]counter
var lock sync.Mutex
var wg sync.WaitGroup
func adder(wid string, n int) {
defer lock.Unlock()
lock.Lock()
d := data[wid]
d.count++
d.value += n
data[wid] = d
}
func main() {
// fmt.Println(os.Getpid())
data = make(map[string]counter)
c := make(chan int)
for w := 1; w <= 3; w++ { //starting 3 workers here
wg.Add(1)
go func(wid string) {
lock.Lock()
data[wid] = counter{}
lock.Unlock()
for v := range c {
adder(wid, v)
}
wg.Done()
}(strconv.Itoa(w)) // worker is given an ID
}
for i := 1; i <= 10; i++ {
c <- i
}
close(c)
wg.Wait()
total := 0
for i, v := range data {
fmt.Println(i, v)
total += v.value
}
fmt.Println(total)
}