goconcurrencydefer-keyword

How working defer in concurrency code in Golang


I have some code:

...
func Run(tasks []Task, n, m int) error {
    ...
    for i := 0; i < n; i++ {
        go func() {
            defer wg.Done()
            for t := range taskCh {
                if atomic.LoadInt32(&errCount) >= int32(m) {
                    return
                }

                if err := t(); err != nil {
                    atomic.AddInt32(&errCount, 1)
                }
            }
        }()
    }

    for _, t := range tasks {
        taskCh <- t
    }
    close(taskCh)
    wg.Wait()
    if atomic.LoadInt32(&errCount) >= int32(m) {
        err = ErrErrorsLimitExceeded
    }
    ...
}

and its work fine, but why its does not work when I writing operating close() wg.Wait and if... on the defer?

    ...
    defer func() {
        close(taskCh)
        wg.Wait()
        if atomic.LoadInt32(&errCount) >= int32(m) {
            err = ErrErrorsLimitExceeded
        }
    }()
    for i := 0; i < n; i++ {
    ...

when variable errCount = 0


Solution

  • It is golang limitation that you cannot change returned variables from defer functions. The correct way to do this is (pay attention to (err error) named return value):

    package main
    
    import "fmt"
    
    func someFunction() (err error) {
        defer func() {
            err = fmt.Errorf("Some error")
        }()
    
        err = fmt.Errorf("Some other error")
    
        return
    }
    
    func main() {
        fmt.Println(someFunction())
    }
    

    https://goplay.tools/snippet/9fwcqTIwhow