Чтение с канала goroutine без блокировки

0

Вопрос

У меня есть две горотины: главная worker и helper что он раскручивается для какой-то помощи. helper могут возникать ошибки, поэтому я использую канал для передачи ошибок из helper к worker.

func helper(c chan <- error) (){
    //do some work
    c <- err // send errors/nil on c
}

Вот как helper() называется:

func worker() error {
    //do some work
    c := make(chan error, 1)
    go helper(c)
    err := <- c
    return err
}

Вопросы:

  • Является ли утверждение err := <- c блокирование worker? Я так не думаю, так как канал буферизован.

  • Если он блокируется, как мне сделать его неблокирующим? Мое требование состоит в том, чтобы иметь worker и его вызывающий абонент продолжает остальную часть работы, не дожидаясь, пока значение появится на канале.

Спасибо.

channel go goroutine
2021-11-24 01:59:57
3

Лучший ответ

2

Вы можете легко проверить

func helper(c chan<- error) {
    time.Sleep(5 * time.Second)
    c <- errors.New("") // send errors/nil on c
}

func worker() error {
    fmt.Println("do one")

    c := make(chan error, 1)
    go helper(c)

    err := <-c
    fmt.Println("do two")

    return err
}

func main() {
    worker()
}

Вопрос: Является ли утверждение ошибочным := Я так не думаю, так как канал буферизован.

Ответ: err := <- c заблокирует работника.

Вопрос: Если он блокируется, как мне сделать его неблокирующим? Мое требование состоит в том, чтобы работник и его вызывающий продолжали выполнять остальную часть работы, не дожидаясь появления значения на канале.

Ответ: Если вы не хотите блокировки, просто удалите err := <-c. Если вам нужно ошибиться в конце, просто двигайтесь err := <-c до самого конца.

Вы не можете читать канал без блокировки, если вы проходите без блокировки, вы больше не можете выполнять этот код, если только ваш код не находится в цикле.

Loop:
    for {
        select {
        case <-c:
            break Loop
        default:
            //default will go through without blocking
        }
        // do something
    }

И вы когда-нибудь видели группу ошибок или группу ожидания?

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

https://github.com/golang/sync/blob/master/errgroup/errgroup.go

https://github.com/golang/go/blob/master/src/sync/waitgroup.go

Или вы можете просто использовать его, выполнить свою функцию, а затем ждать ошибки в любом месте, где захотите.

2021-12-01 21:31:34
1

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

func worker() error {
    //do some work
    c := make(chan error, 1)
    go helper(c)
    //do rest of the work
    return <-c
}
2021-11-24 02:54:28

Ну, разве рабочий() не будет заблокирован до тех пор, пока значение не появится на c?
Someone

Кроме того, я только что отредактировал worker(). Он возвращает вызывающему объекту ошибку/ноль. Итак, будет ли эта операция заблокирована?
Someone

Да, эта конкретная операция будет заблокирована до тех пор, пока помощник не отправит error или nil на канал. Но работник блокируется только после того, как он выполнил всю свою работу.
Chandra Sekar

Но это блокирует возможность worker. Есть ли способ сделать его неблокирующим?
Someone

Если работник и, следовательно, его вызывающий абонент не ждет завершения работы помощника, как он может вернуть ошибку от помощника?
Chandra Sekar
0

Я думаю, вам нужен этот код..

запустите этот код

package main

import (
    "log"
    "sync"
)

func helper(c chan<- error) {

    for {
        var err error = nil
        // do job

        if err != nil {
            c <- err // send errors/nil on c
            break
        }
    }

}

func worker(c chan error) error {
    log.Println("first log")

    go func() {
        helper(c)
    }()

    count := 1
    Loop:
        for {
            select {
            case err := <- c :
                return err
            default:
                log.Println(count, " log")
                count++
                isFinished := false
                // do your job
                if isFinished {
                    break Loop // remove this when you test

                }
            }
        }
    return nil
}

func main() {
    wg := sync.WaitGroup{}
    wg.Add(1)
    go func() {
        c := make(chan error, 1)
        worker(c)
        wg.Done()
    }()
    wg.Wait()
}
2021-11-24 02:35:53

Можете ли вы объяснить, отредактировав этот ответ, почему это поможет? Интересно, будет ли это полезно, если не автору вопроса, то будущим читателям.
halfer

На других языках

Эта страница на других языках

Italiano
..................................................................................................................
Polski
..................................................................................................................
Română
..................................................................................................................
한국어
..................................................................................................................
हिन्दी
..................................................................................................................
Français
..................................................................................................................
Türk
..................................................................................................................
Česk
..................................................................................................................
Português
..................................................................................................................
ไทย
..................................................................................................................
中文
..................................................................................................................
Español
..................................................................................................................
Slovenský
..................................................................................................................