Goroutines(协程)、Callbacks(回调函数)和sync.WaitGroup(同步等待组)

huangapple go评论79阅读模式
英文:

Goroutines, Callbacks and sync.WaitGroup

问题

以下是代码的翻译:

package main

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

func callbackWithTimeout(cbFunc func() ([]byte, error), timeout time.Duration) {
	defer wg.Done() //我不希望这个函数知道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) {
			//我觉得我应该在这里使用defer
			return nil, nil
		}
		callbackWithTimeout(cbFunc, time.Duration(4*time.Second))
	}()
	println("some line")
	wg.Wait()
}

callbackWithTimeout函数中,我不想使用defer wg.Done(),因为callbackWithTimeout()函数不应该关心wg.Done()。我应该如何实现这样的功能?即在callbackWithTimeout中移除任何sync.WaitGroup?我在这里有一些问题理解关注点的分离,因为回调函数不应该知道关于waitgroup的事情,但在这种情况下,似乎没有其他选择?

我觉得应该由调用者(在这种情况下是cbFunc)负责wg.Done(),但是缺乏关于如何在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()
}
英文:

With the following code:

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()
}

In function callbackWithTimeout, I don't want to use defer wg.Done() because it's not callbackWithTimeout()'s concern to wg.Done(). How do I go about implementing such a thing? i.e., remove any sync.WaitGroup in callbackWithTimeout? I have a bit of problem understanding the separation of concerns here as a callback'er function should not have to know about waitgroups but in this case it seems, I have no other choice?

I feel like it should be a caller's responsibility to wg.Done() (which in this case is the cbFunc) but lack any concise reference to documentation or ideas on how to implement it in Go because by definition, all a callback function does is call the function back. So, where I am doing it wrong?


Silly assumptions were made by yours truly during refactoring. Working code below. Many thanks.

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

得分: 3

可能是这样的吗?

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() // 将其移到这里
		cbFunc := func() ([]byte, error) {
			// 我觉得我应该在这里使用defer
			return nil, nil
		}
		callbackWithTimeout(cbFunc, time.Duration(4*time.Second))
	}()

	println("some line")

	wg.Wait()
}

请注意,这只是代码的翻译,我无法运行代码或提供任何关于代码功能或逻辑的保证。

英文:

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()
}

huangapple
  • 本文由 发表于 2017年8月13日 21:17:03
  • 转载请务必保留本文链接:https://go.coder-hub.com/45660762.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定