我的目标是使用goroutine和通道,我想学习如何在不同goroutine之间进行通信,并且希望避免死锁。我设法使用了sync.WaitGroup
,它工作正常。
但是我收到一条错误消息
1次紧急:同步:WaitGroup计数器为负
goroutine 19 [运行中]:
该程序的目标很简单。
代码:
package main
import (
"fmt"
"sync"
"time"
)
type developer struct {
name string
setTimeForWebsite time.Time
}
type website struct {
owner string
created time.Time
}
var developers []developer
var websites []website
// A function to create a developer
func hireDeveloper(wg *sync.WaitGroup, workNumber int,
developerCreatedc chan developer, devs []developer) {
defer wg.Done()
developerNumber := fmt.Sprintf("developer_%d", workNumber)
d := developer{name: developerNumber}
fmt.Println("Hired", d.name)
developerCreatedc <- d
}
// A function to create a website
func createComputer(wg *sync.WaitGroup, developerCreatedc chan developer, websitePerComputer int, websites []website) {
defer wg.Done()
// Assign the developer to the website creation // N number of the website
d := <-developerCreatedc
for i := 0; i <= websitePerComputer; i++ {
fmt.Println("Delegate", d.name, "to set the time to start
building the website")
d.setTimeForWebsite = time.Now()
fmt.Println(d.name, "Finish calculating to build the website", d.setTimeForWebsite)
web := website{owner: d.name, created: d.setTimeForWebsite}
websites = append(websites, web)
fmt.Println(len(websites))
time.Sleep(time.Second * 2)
fmt.Println(d.name, "Created website at", web.created)
}
}
func main() {
// Make a channel for when developer is hired
developerCreatedC := make(chan developer)
// create a sync group
wg := &sync.WaitGroup{}
// Assume that number of websites are 20
numberOfWebsites := 20
// Assume that number of developers are 5
numberOfDevelopers := 5
// Divide the websites to 5 developers
websitePerDeveloper := numberOfWebsites / numberOfDevelopers
// add the sync
wg.Add(1)
for i := 1; i <= numberOfDevelopers; i++ {
go func(producerNumber int) {
hireDeveloper(wg, producerNumber, developerCreatedC,
developers)
}(i)
}
wg.Add(1)
for i := 1; i <= websitePerDeveloper; i++ {
createComputer(wg, developerCreatedC, 5, websites)
}
wg.Wait()
}
游乐场 https://play.golang.org/p/QSOv5jp3T94
有时这种行为有点,一个开发人员创建了4个以上的网站,即使应该只创建4个。
谢谢
答案 0 :(得分:2)
wg.Add()
应该等于您正在运行的go例程的数量。此外,createComputer(wg, developerCreatedC, websitePerDeveloper, websites)
应该基于开发人员。
package main
import (
"fmt"
"sync"
"time"
)
type developer struct {
name string
setTimeForWebsite time.Time
}
type website struct {
owner string
created time.Time
}
var developers []developer
var websites []website
// A function to create a developer
func hireDeveloper(wg *sync.WaitGroup, workNumber int, developerCreatedc chan developer, devs []developer) {
defer wg.Done()
developerNumber := fmt.Sprintf("developer_%d", workNumber)
d := developer{name: developerNumber}
fmt.Println("Hired", d.name)
developerCreatedc <- d
}
// A function to create a website
func createComputer(wg *sync.WaitGroup, developerCreatedc chan developer, websitePerComputer int, websites []website) {
defer wg.Done()
// Assign the developer to the website creation // N number of the website
d := <-developerCreatedc
for i := 0; i <= websitePerComputer; i++ {
fmt.Println("Delegate", d.name, "to set the time to start building the website")
d.setTimeForWebsite = time.Now()
web := website{owner: d.name, created: d.setTimeForWebsite}
websites = append(websites, web)
fmt.Println(len(websites))
time.Sleep(time.Second * 2)
fmt.Println(d.name, "Created website at", web.created)
}
}
func main() {
// Make a channel for when developer is hired
developerCreatedC := make(chan developer)
// create a sync group
wg := &sync.WaitGroup{}
// Assume that number of websites are 20
numberOfWebsites := 20
// Assume that number of developers are 5
numberOfDevelopers := 5
// Divide the websites to 5 developers
websitePerDeveloper := numberOfWebsites / numberOfDevelopers
for i := 1; i <= numberOfDevelopers; i++ {
// add the sync
wg.Add(1)
go func(producerNumber int) {
hireDeveloper(wg, producerNumber, developerCreatedC, developers)
}(i)
wg.Add(1)
go createComputer(wg, developerCreatedC, websitePerDeveloper, websites)
}
wg.Wait()
}
答案 1 :(得分:0)
收到错误是因为您在循环之前执行了wg.Add(1)
。
每次对hireDeveloper()
和createComputer()
的调用都会调用wg.Done()
,因此已经在第一个for循环wg
中倒数到-4,这是不可能的,因此很恐慌。>
可能的解决方案是:
wg.Add(numberOfDevelopers)
for i := 1; i <= numberOfDevelopers; i++ {...}
....
wg.Add(websitePerDeveloper)
for i := 1; i <= websitePerDeveloper; i++ {...}
或者您将wg.Add插入for循环:
for i := 1; i <= numberOfDevelopers; i++ {
wg.Add(1)
go func(producerNumber int) {
hireDeveloper(wg, producerNumber, developerCreatedC,
developers)
}(i)
}