duanfang7270 2018-11-22 14:52
浏览 32
已采纳

紧急:同步:否WaitGroup计数器

My goal is to use goroutines and channel, i want to learn how to communicate between different goroutines and i want to avoid deadlock. I managed to use sync.WaitGroup and it is working just fine.

However I received an error saying that

1 panic: sync: negative WaitGroup counter

goroutine 19 [running]:

The goal of this program is simple.

  1. Create a developer
  2. Assign him/her to create a website
  3. Depends on the number of the websites
  4. Once website is done then append it to the array
  5. Let there are 20 websites and 5 developers
  6. Each developer will take create 4 websites and append it to the websites array
  7. I want to do it concurrently so that other developers don't have to wait

The code:

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

The playground https://play.golang.org/p/QSOv5jp3T94

The behaviour is a bit sometimes, one developer created more than 4 websites, even though it is supposed to create only 4

Thanks

  • 写回答

2条回答 默认 最新

  • douxingti9307 2018-11-22 15:13
    关注

    wg.Add() should be equal to the number number of go routine you are running. Also createComputer(wg, developerCreatedC, websitePerDeveloper, websites) should be per developer basis.

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

报告相同问题?

悬赏问题

  • ¥20 机器学习能否像多层线性模型一样处理嵌套数据
  • ¥20 西门子S7-Graph,S7-300,梯形图
  • ¥50 用易语言http 访问不了网页
  • ¥50 safari浏览器fetch提交数据后数据丢失问题
  • ¥15 matlab不知道怎么改,求解答!!
  • ¥15 永磁直线电机的电流环pi调不出来
  • ¥15 用stata实现聚类的代码
  • ¥15 请问paddlehub能支持移动端开发吗?在Android studio上该如何部署?
  • ¥20 docker里部署springboot项目,访问不到扬声器
  • ¥15 netty整合springboot之后自动重连失效