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