Goroutines,Callbacks和sync.WaitGroup

时间:2017-08-13 13:17:03

标签: go callback goroutine

使用以下代码:

package main

import (
    "github.com/davecgh/go-spew/spew"
    "sync"
    "time"
)
func callbackWithTimeout(cbFunc func() ([]byte, error), timeout time.Duration) {
    defer wg.Done() //I don't want this function to know about sync.WaitGroup
    time.Sleep(timeout)
    d, e := cbFunc()
    spew.Dump(d)
    spew.Dump(e)
}
var wg sync.WaitGroup
func main() {
    wg.Add(1)
    go func() {
        cbFunc := func() ([]byte, error) {
            //I feel like I should be able to defer here instead
            return nil, nil
        }
        callbackWithTimeout(cbFunc, time.Duration(4*time.Second))
    }()
    println("some line")
    wg.Wait()
}

在功能callbackWithTimeout中,我不想使用defer wg.Done(),因为它不是callbackWithTimeout()wg.Done()的关注。我该如何实施这样的事情?即,删除sync.WaitGroup中的所有callbackWithTimeout?我有一些问题需要理解这里的关注点分离,因为回调函数不应该知道waitgroups,但在这种情况下似乎,我别无选择?

我觉得wg.Done()(在这种情况下是cbFunc)应该是来电者的责任,但缺乏对文档的简明参考或关于如何在Go中实现它的想法,因为根据定义,所有回调函数都会调用该函数。那么,我做错了什么?

你在重构过程中做出了愚蠢的假设。下面的工作代码。非常感谢。

package main

import (
    "errors"
    "github.com/davecgh/go-spew/spew"
    "sync"
    "time"
)

func callbackWithTimeout(cbFunc func() ([]byte, error), timeout time.Duration) {
    time.Sleep(timeout)
    d, e := cbFunc()
    spew.Dump(d)
    spew.Dump(e)
}

func main() {
    var wg sync.WaitGroup
    wg.Add(1)
    go func() {
        defer wg.Done()
        callbackWithTimeout(func() ([]byte, error) {
            b := []byte{1, 2, 3, 4}
            e := errors.New("error123")
            return b, e
        }, time.Duration(2*time.Second))
    }()
    println("some line")
    wg.Wait()
}

1 个答案:

答案 0 :(得分:3)

May be like this?

package main

import (
    "sync"
    "time"

    "github.com/davecgh/go-spew/spew"
)

func callbackWithTimeout(cbFunc func() ([]byte, error), timeout time.Duration) {
    time.Sleep(timeout)
    d, e := cbFunc()
    spew.Dump(d)
    spew.Dump(e)
}

func main() {
    var wg sync.WaitGroup

    wg.Add(1)

    go func() {
        defer wg.Done() // move it here
        cbFunc := func() ([]byte, error) {
            //I feel like I should be able to defer here instead
            return nil, nil
        }
        callbackWithTimeout(cbFunc, time.Duration(4*time.Second))
    }()

    println("some line")

    wg.Wait()
}