подсчитывать/отображать количество активных горутин

У меня есть очередь и функция, которая выполняет как удаление из очереди, так и постановку в очередь. Я хочу убедиться, что в очереди работает нужное количество горутин, если в списке есть что-то.

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

Ссылка на игровую площадку

var element int

func deen(queue chan int) {

    element := <-queue
    fmt.Println("element is ", element)
    if element%2 == 0 {
        fmt.Println("new element is ", element)
        queue <- (element*100 + 11)
        queue <- (element*100 + 33)
    }
}

func main() {
    queue := make(chan int, 10)
    queue <- 1
    queue <- 2
    queue <- 3
    queue <- 0 
    for len(queue) != 0 {
        for i := 0; i < 2; i++ {
            go deen(queue)
        }
    }
    fmt.Scanln()
    fmt.Println("list is has len", len(queue)) //this must be 0

}    

person meto    schedule 26.09.2014    source источник


Ответы (1)


Есть runtime.NumGoroutine, но вы подходите к этому неправильно.

  1. Ваши циклы будут продолжать порождать горутины.
  2. это будет излишне сжигать циклы процессора из-за цикла for.

Один из подходов — использовать sync.WaitGroup.

func deen(wg *sync.WaitGroup, queue chan int) {
    for element := range queue {
        fmt.Println("element is ", element)
        if element%2 == 0 {
            fmt.Println("new element is ", element)
            wg.Add(2)
            queue <- (element*100 + 11)
            queue <- (element*100 + 33)
        }
        wg.Done()
    }
}

func main() {
    var wg sync.WaitGroup
    queue := make(chan int, 10)
    queue <- 1
    queue <- 2
    queue <- 3
    queue <- 0
    for i := 0; i < 4; i++ {
        wg.Add(1)
        go deen(&wg, queue)
    }
    wg.Wait()
    close(queue)
    fmt.Println("list len", len(queue)) //this must be 0

}

игровая площадка

--- старая глючная версия с гонками ---

func deen(wg *sync.WaitGroup, queue chan int) {
    for element := range queue {
        wg.Done()
        fmt.Println("element is ", element)
        if element%2 == 0 {
            fmt.Println("new element is ", element)
            wg.Add(2)
            queue <- (element*100 + 11)
            queue <- (element*100 + 33)
        }
    }
}

func main() {
    var wg sync.WaitGroup
    queue := make(chan int, 10)
    queue <- 1
    queue <- 2
    queue <- 3
    queue <- 0
    for i := 0; i < 4; i++ {
        wg.Add(1)
        go deen(&wg, queue)
    }
    wg.Wait()
    close(queue)
    fmt.Println("list is has len", len(queue)) //this must be 0
}

детская площадка

person OneOfOne    schedule 26.09.2014
comment
Спасибо, но разве WaitGroup не ждет, когда что-то будет сделано? Я на самом деле хочу убедиться, что они не умрут слишком рано по какой-то внешней причине. - person meto; 26.09.2014
comment
@meto Горутины так не умирают, если умирает горутина, то ваша программа, скорее всего, разбилась, я добавлю пример. - person OneOfOne; 26.09.2014
comment
это очень интересно. Просто быстрый дополнительный вопрос. Часть wg.Done можно было разместить и после Println, но уж точно перед if, верно? - person meto; 26.09.2014
comment
@meto на самом деле для этого конкретного примера это вообще не имеет значения, пока оно находится за пределами if. - person OneOfOne; 26.09.2014
comment
Я сделал небольшую модификацию (wg.Add находится в начале подпрограммы). Вам это кажется правильным? play.golang.org/p/KWrrLVzzBf - person meto; 29.09.2014
comment
@meto Нет, поскольку wg.add не будет выполняться до тех пор, пока вы не выйдете из основного цикла for, горутины не будут выполняться немедленно. - person OneOfOne; 29.09.2014
comment
@OneOfOne выглядит так, как будто приведенная выше программа паникует. wg.Done() не должно быть сразу после получения значения из очереди. Мы пытаемся протолкнуть элемент даже после того, как канал закрылся. - person Sourav Prem; 06.07.2020
comment
@OneOfOne работает, когда wg.Done() перемещается после printf . Может ли кто-нибудь объяснить, почему вышеуказанная программа работает, когда wg.Done() находится после printf и паникует, если до нее. Не могу этого понять. - person Sourav Prem; 08.07.2020