Go 常规生产者消费者模式恐慌

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

我已经实现了本文中提到的goroutine的生产者-消费者模式。但它有时会惊慌失措,错误是:“惊慌:同步:负等待组计数器”。我有如下示例代码:

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以并行计算的方式运行,就像你说的那样。