Go 如何在单个程序中使用多个sync.WaitGroup

Go 如何在单个程序中使用多个sync.WaitGroup,go,concurrency,Go,Concurrency,在我的围棋计划中,我为每个部门建立了多个工人小组。 我想在退出该计划之前等待每个部门的工作人员完成 我不能使用单个WaitGroups,因为在实际场景中,我可能必须结束任何特定的部门,只需要等待 这是代码的简化版本,但它会因为一条消息而惊慌失措 死机:运行时错误:无效内存地址或零指针取消引用 主程序包 进口( “fmt” “同步” “时间” ) var wgMap map[string]*sync.WaitGroup func deptWorker(dName字符串,id int){ 延迟wgM

在我的围棋计划中,我为每个部门建立了多个工人小组。 我想在退出该计划之前等待每个部门的工作人员完成

我不能使用单个WaitGroups,因为在实际场景中,我可能必须结束任何特定的部门,只需要等待

这是代码的简化版本,但它会因为一条消息而惊慌失措

死机:运行时错误:无效内存地址或零指针取消引用

主程序包
进口(
“fmt”
“同步”
“时间”
)
var wgMap map[string]*sync.WaitGroup
func deptWorker(dName字符串,id int){
延迟wgMap[dName].Done()
fmt.Printf(“部门%s:工人%d开始\n”,数据名,id)
时间。睡眠(时间。秒)
fmt.Printf(“部门%s:工作人员%d已完成”,数据名,id)
}
职能部门(dName字符串){
var wg sync.WaitGroup

对于i:=1;iTwo-fix-nil-panic,您只需使用

var wgMap = map[string]*sync.WaitGroup{} 
它将初始化映射。然而,在我看来,最好在这里创建一个新的抽象,让我们把它命名为“WaitMap”

它可以通过以下方式实现:

package main

import (
    "fmt"
    "sync"
    "time"
)

type WaitMapObject struct {
    wg map[string]int
    mu sync.Mutex
    cond sync.Cond
}

func WaitMap() *WaitMapObject {
    m := &WaitMapObject{}
    m.wg = make(map[string]int)
    m.cond.L = &m.mu
    return m
}

func (m *WaitMapObject) Wait(name string) {
    m.mu.Lock()
    for m.wg[name] != 0 {
        m.cond.Wait()
    }
    m.mu.Unlock()
}

func (m *WaitMapObject) Done(name string) {
    m.mu.Lock()
    no := m.wg[name] - 1
    if no < 0 {
        panic("")
    }
    m.wg[name] = no
    m.mu.Unlock()
    m.cond.Broadcast()
}

func (m *WaitMapObject) Add(name string, no int) {
    m.mu.Lock()
    m.wg[name] = m.wg[name] + no
    m.mu.Unlock()
}

func deptWorker(dName string, id int, wm *WaitMapObject) {
    defer wm.Done(dName)
    fmt.Printf("Department %s : Worker %d starting\n", dName, id)
    time.Sleep(time.Second)
    fmt.Printf("Department %s :  Worker %d done\n", dName, id)
}

func department(dName string, wm *WaitMapObject) {
    for i := 1; i <= 3; i++ {
        wm.Add(dName,1)
        go deptWorker(dName, i, wm)
    }
    wm.Done(dName)
}

func main() {
    wm := WaitMap()

    wm.Add("mediacal",1)
    go department("medical", wm)

    wm.Add("electronics",1)
    go department("electronics", wm)

    wm.Wait("medical")
    wm.Wait("electronics")
}
主程序包
进口(
“fmt”
“同步”
“时间”
)
类型WaitMapObject结构{
wg map[string]int
mu-sync.Mutex
康德,康德
}
func WaitMap()*WaitMapObject{
m:=&WaitMapObject{}
m、 wg=make(映射[string]int)
m、 条件L=&m.mu
返回m
}
func(m*WaitMapObject)等待(名称字符串){
m、 木锁()
对于m.wg[name]!=0{
m、 等等
}
m、 mu.Unlock()
}
func(m*WaitMapObject)完成(名称字符串){
m、 木锁()
编号:=m.wg[名称]-1
如果否<0{
恐慌(“”)
}
m、 wg[名称]=否
m、 mu.Unlock()
m、 康德广播公司
}
func(m*WaitMapObject)添加(名称字符串,无int){
m、 木锁()
m、 wg[name]=m.wg[name]+编号
m、 mu.Unlock()
}
func deptWorker(dName字符串,id int,wm*WaitMapObject){
延迟wm.Done(dName)
fmt.Printf(“部门%s:工人%d开始\n”,数据名,id)
时间。睡眠(时间。秒)
fmt.Printf(“部门%s:工作人员%d已完成”,数据名,id)
}
职能部门(dName字符串,wm*WaitMapObject){

对于i:=1;我请从panic中读取整个堆栈跟踪,并将其包含在问题中。它会准确地告诉您哪一行有问题。但问题很可能是您从未初始化过
wgMap
变量。还要注意,这样的waitgroup映射非常不常规,可能是个坏主意。您需要保护使用互斥锁将其删除,这将非常笨拙。对不起,我错过了make(映射…)。但添加这一点也无助于解决问题。我想我必须更改架构。我现在必须为每个部门运行多个go流程。并使用主流程协调流程。不要在注释中粘贴堆栈跟踪。这是不可能的。请更新您的问题。第二个示例仍然包含种族可能导致等待组恐慌的情况。是的,我明白了。所以第二个不正确,我删除了它。
package main

import (
    "fmt"
    "sync"
    "time"
)

type WaitMapObject struct {
    wg map[string]int
    mu sync.Mutex
    cond sync.Cond
}

func WaitMap() *WaitMapObject {
    m := &WaitMapObject{}
    m.wg = make(map[string]int)
    m.cond.L = &m.mu
    return m
}

func (m *WaitMapObject) Wait(name string) {
    m.mu.Lock()
    for m.wg[name] != 0 {
        m.cond.Wait()
    }
    m.mu.Unlock()
}

func (m *WaitMapObject) Done(name string) {
    m.mu.Lock()
    no := m.wg[name] - 1
    if no < 0 {
        panic("")
    }
    m.wg[name] = no
    m.mu.Unlock()
    m.cond.Broadcast()
}

func (m *WaitMapObject) Add(name string, no int) {
    m.mu.Lock()
    m.wg[name] = m.wg[name] + no
    m.mu.Unlock()
}

func deptWorker(dName string, id int, wm *WaitMapObject) {
    defer wm.Done(dName)
    fmt.Printf("Department %s : Worker %d starting\n", dName, id)
    time.Sleep(time.Second)
    fmt.Printf("Department %s :  Worker %d done\n", dName, id)
}

func department(dName string, wm *WaitMapObject) {
    for i := 1; i <= 3; i++ {
        wm.Add(dName,1)
        go deptWorker(dName, i, wm)
    }
    wm.Done(dName)
}

func main() {
    wm := WaitMap()

    wm.Add("mediacal",1)
    go department("medical", wm)

    wm.Add("electronics",1)
    go department("electronics", wm)

    wm.Wait("medical")
    wm.Wait("electronics")
}