паника: синхронизация: отрицательный счетчик WaitGroup - PullRequest
0 голосов
/ 22 ноября 2018

Моя цель - использовать программы и каналы, я хочу научиться общаться между различными программами и избегать тупиковых ситуаций.Мне удалось использовать sync.WaitGroup, и он работает просто отлично.

Однако я получил сообщение о том, что

1 паника: синхронизация: отрицательный счетчик WaitGroup

goroutine 19 [выполняется]:

Цель этой программы проста.

  1. Создать разработчика
  2. Назначить его / ее для создания веб-сайта
  3. Зависит отколичество сайтов
  4. Как только сайт будет создан, добавьте его в массив
  5. Пусть будет 20 сайтов и 5 разработчиков
  6. Каждый разработчик создаст 4 сайта и добавит ихк массиву веб-сайтов
  7. Я хочу сделать это одновременно, чтобы другим разработчикам не пришлось ждать

Код:

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

Спасибо

Ответы [ 2 ]

0 голосов
/ 22 ноября 2018

wg.Add() должно быть равно количеству запущенных вами подпрограмм.Также 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()
}
0 голосов
/ 22 ноября 2018

Вы получаете ошибку, потому что вы делаете 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. Добавьте в цикл for:

      for i := 1; i <= numberOfDevelopers; i++ {
        wg.Add(1)
        go func(producerNumber int) {
            hireDeveloper(wg, producerNumber, developerCreatedC, 
            developers)
        }(i)
   }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...