Запись данных в один и тот же канал из разных подпрограмм go работает нормально без группы ожидания - PullRequest
0 голосов
/ 11 марта 2019

При записи данных в один и тот же канал с использованием нескольких процедур go с waitgroup после ожидания wg.Wait () получает исключение, сообщающее, что все процедуры go находятся в спящем режиме или в режиме deedlock.

package main

import (
    "fmt"
    "runtime"
    "sync"
)

var wg sync.WaitGroup

func CreateMultipleRoutines() {
    ch := make(chan int)

    for i := 0; i < 10; i++ { // creates 10 go routines and adds to waitgroup
        wg.Add(1)
        go func() {
            for j := 0; j < 10; j++ {
                ch <- j
            }
            wg.Done() // indication of go routine is done to main routine
        }()
    }

    fmt.Println(runtime.NumGoroutine())
    wg.Wait()           //wait for all go routines to complete
    close(ch)           // closing channel after completion of wait fo go routines
    for v := range ch { // range can be used since channel is closed
        fmt.Println(v)
    }
    fmt.Println("About to exit program ...")
}

Когда я попытался реализовать это без группы ожидания, я могу читать данные из канала, зацикливая точное число раз, когда данные отправляются в канал, но я не могу выбрать диапазон, поскольку при закрытии канала будет паника. вот пример кода

package main

import (
    "fmt"
    "runtime"
)

func main() {
    ch := make(chan int)


    for i := 0; i < 10; i++ { // creates 10 go routines and adds to waitgroup
        go func(i int) {
            for j := 0; j < 10; j++ {
                ch <- j * i
            }
        }(i)
    }

    fmt.Println(runtime.NumGoroutine())

    for v := 0; v < 100; v++ {
        fmt.Println(<-ch)
    }
    fmt.Println("About to exit program ...")
}

Я хочу понять, почему группа ожидания в состоянии ожидания все еще ждет, хотя все процедуры go передаются в виде сообщения Done (), в результате которого inturn делает число операций go равным нулю

Ответы [ 2 ]

2 голосов
/ 11 марта 2019

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

  1. Вы закрываете канал перед чтением с него.
  2. Вы не получаете преимущества использования 10 процедур из-за вашихканал 1 "размером".Таким образом, одна программа производит один результат за один раз.

Мое решение состояло бы в том, чтобы порождать новую программу для контроля, если 10 программ завершили свою работу.Там вы будете использовать ваш WaitGroup.

Тогда код будет выглядеть так:

package main

import (
    "fmt"
    "runtime"
    "sync"
)

var wg sync.WaitGroup

func main() {
    ch := make(chan int, 10)

    for i := 0; i < 10; i++ { // creates 10 go routines and adds to waitgroup
        wg.Add(1)
        go func() {
            for j := 0; j < 10; j++ {
                ch <- j
            }
            wg.Done() // indication of go routine is done to main routine
        }()
    }

    go func(){
        wg.Wait()
        close(ch)
    }()

    fmt.Println(runtime.NumGoroutine())
    for v := range ch { // range can be used since channel is closed
        fmt.Println(v)
    }
    fmt.Println("About to exit program ...")
}
1 голос
/ 11 марта 2019

По умолчанию chan не содержит никаких элементов, поэтому все подпрограммы go при отправке блокируются, пока что-то из них не будет считано. Они никогда не достигают утверждения wg.Done().

Решением было бы закрыть канал в своей собственной рутине. Оберните ваши wg.Wait() и close(ch) строки следующим образом:

go func() {
    wg.Wait() //wait for all go routines to complete
    close(ch) // closing channel after completion of wait fo go routines
}()

Затем вы можете выбрать диапазон канала, который закроется только после того, как все подпрограммы отправки завершены (и неявно все значения получены).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...