Go 常规生产者消费者模式恐慌
我已经实现了本文中提到的goroutine的生产者-消费者模式。但它有时会惊慌失措,错误是:“惊慌:同步:负等待组计数器”。我有如下示例代码:Go 常规生产者消费者模式恐慌,go,goroutine,Go,Goroutine,我已经实现了本文中提到的goroutine的生产者-消费者模式。但它有时会惊慌失措,错误是:“惊慌:同步:负等待组计数器”。我有如下示例代码: package main import ( "bytes" "encoding/gob" "log" _ "net/http/pprof" "sync" ) // Test ... type Test struct { PropA []int PropB []int } // Clone de
package main
import (
"bytes"
"encoding/gob"
"log"
_ "net/http/pprof"
"sync"
)
// Test ...
type Test struct {
PropA []int
PropB []int
}
// Clone deep-copies a to b
func Clone(a, b interface{}) {
buff := new(bytes.Buffer)
enc := gob.NewEncoder(buff)
dec := gob.NewDecoder(buff)
enc.Encode(a)
dec.Decode(b)
}
func main() {
test := Test{
PropA: []int{211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222},
PropB: []int{111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124},
}
var wg, wg2 sync.WaitGroup
ch := make(chan int, 5)
results := make(chan Test, 5)
// start consumers
for i := 0; i < 4; i++ {
wg.Add(1)
go func(ch <-chan int, results chan<- Test) {
defer wg.Done()
for propA := range ch {
var temp Test
Clone(&test, &temp)
temp.PropA = []int{propA}
results <- temp
}
}(ch, results)
}
// start producing
go func(ch chan<- int) {
defer wg.Done()
for _, propA := range test.PropA {
ch <- propA
}
close(ch)
}(ch)
wg2.Add(1)
go func(results <-chan Test) {
defer wg2.Done()
for tt := range results {
log.Printf("finished propA %+v\n", tt.PropA[0])
}
}(results)
wg.Wait() // Wait all consumers to finish processing jobs
// All jobs are processed, no more values will be sent on results:
close(results)
wg2.Wait()
}
看来wg.Done()有两点可能是问题所在。 我重构了您的代码,只添加了wg.Done()的一个点,并从您添加的循环中删除了wg.Add(1)。
代码因此,wg.Done()中有两点可能是问题所在。 我重构了您的代码,只添加了wg.Done()的一个点,并从您添加的循环中删除了wg.Add(1)。
Code您在
wg
上的簿记被一次关闭,因为您的制作人调用了wg.Done()
,但没有调用Add()
来解释它。恐慌与go调度程序的可变性有关,但一旦您看到修复,我相信您将看到如何获得“负WaitGroup计数器”和/或“关闭通道发送”,所有这些都取决于时间
修复很简单,只需在开始制作之前添加一个wg.add()
...
wg.Add(1)
// start producing
go func(ch chan<- int) {
defer wg.Done()
for _, propA := range test.PropA {
ch <- propA
}
close(ch)
}(ch)
...
。。。
工作组.添加(1)
//开始生产
go func(ch chan你在wg
上的簿记被关闭了一次,因为你的制作人调用了wg.Done()
,但是没有调用Add()
来解释它。恐慌与go调度程序的可变性有关,但是一旦你看到修复,我相信你会看到如何获得“负等待组计数器”和/或“封闭通道发送”,全部取决于定时
修复很简单,只需在开始制作之前添加一个wg.add()
...
wg.Add(1)
// start producing
go func(ch chan<- int) {
defer wg.Done()
for _, propA := range test.PropA {
ch <- propA
}
close(ch)
}(ch)
...
。。。
工作组.添加(1)
//开始生产
go func(这里有一个defer wg.Done()
在制作人goroutine中。但是我没有看到相应的wg.Add
。在哪一行出现恐慌?@EugeneLisitsky我为恐慌案例添加了stacktrace,因为这不是完整的代码。第75/100行不存在。@C4u 75和100用于waitgroup.go
这是golang源代码…有一个延迟wg.Done()
在制作人goroutine中。但是我没有看到相应的wg.Add
。在哪一行出现恐慌?@EugeneLisitsky我为恐慌案例添加了stacktrace,因为这不是完整的代码。第75/100行不存在。@C4u 75和100用于waitgroup.go
这是golang的源代码…它将失去目的异步并行计算的ose。它将同步进行计算,这与没有goroutine类似。我在consumer中使用了for loop
,将作业分配给不同的工作人员进行并行计算。我编辑了代码,使goroutine以并行计算的方式运行,就像你说的那样。这将失去异步的目的ous并行计算。它将同步进行计算,这类似于没有goroutine。我在consumer中使用了for loop
,将作业分配给不同的工作人员进行并行计算。我编辑了代码,使goroutine以并行计算的方式运行,就像你说的那样。