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

问题描述 投票:-2回答:1

在我的Go程序中,我为每个部门启动了多个工作组。我想等每个部门的工作人员完成后再退出程序

我不能使用单个WaitGroup,因为在实际情况下,我可能不得不终止任何特定部门,而只需要等待。

这是简化的代码版本,但出现消息时会出现恐慌

紧急:运行时错误:无效的内存地址或nil指针取消引用

package main

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

var wgMap map[string]*sync.WaitGroup

func deptWorker(dName string, id int) {
    defer wgMap[dName].Done()
    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) {
    var wg sync.WaitGroup
    for i := 1; i <= 3; i++ {
        wg.Add(1)
        go deptWorker(dName, i)
    }
    wgMap[dName] = &wg
}

func main() {
    go department("medical")
    go department("electronics")

    wgMap["medical"].Wait()
    wgMap["electronics"].Wait()
}
go concurrency
1个回答
0
投票

您只需要使用两次即可解决nil紧急情况

var wgMap map[string]*sync.WaitGroup{} 

它将初始化地图。但是,实际上您必须创建一个新的抽象,如WaitGroupMap。等待点不只一个,因为例如goroutine可以在您访问支票上的地图之后启动。

可以用这种方式实现:

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.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()
}

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)
    }
}

func main() {
    wm := WaitMap()

    go department("medical", wm)
    go department("electronics", wm)

    wm.Wait("medical")
    wm.Wait("electronics")
}
© www.soinside.com 2019 - 2024. All rights reserved.