Как использовать несколько syn c .WaitGroup в одной программе - PullRequest
0 голосов
/ 09 февраля 2020

В моей программе Go я запускаю несколько рабочих групп для каждого отдела. Я хочу дождаться завершения работы сотрудников из каждого отдела, прежде чем выйти из программы

Я не могу использовать одну группу WaitGroups, поскольку в реальном сценарии мне может потребоваться завершить работу какого-либо конкретного отдела и ждать только этого.

Это упрощенная версия кода, но она паникует сообщением

pani c: ошибка времени выполнения: неверный адрес памяти или разыменование нулевого указателя

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

1 Ответ

1 голос
/ 09 февраля 2020

Two fix nil pani c, вам просто нужно использовать

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")
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...