英文:
How to pass WaitGroup to a sequential function call?
问题
我有一个函数,可以在单独的goroutine中按顺序或并发调用。
我想确保在主goroutine完成之前完全执行函数,所以我将*sync.WaitGroup参数传递给函数。现在,在某些地方,函数需要按顺序调用。
我可以像这样将nil waitGroup传递给函数:
func my_func(wg *sync.WaitGroup){
if wg != nil{
defer wg.Done()
}
// 执行任务
}
func main(){
my_func(nil) // 顺序调用
wg := sync.WaitGroup{}
wg.Add(1)
go my_func(&wg) // 并发调用
wg.Wait()
}
有没有更好的方法来实现这个?
英文:
I have a function which can be called sequentially or concurrently in separate goroutine.
I want to ensure that function is executed completely before main goroutine finishes, so I am passing *sync.WaitGroup argument to the function. Now, at some places the function is to be called sequentially.
I can pass nil waitGroup to the function like this:
func my_func(wg *sync.WaitGroup){
if wg != nil{
defer wg.Done()
}
// do the task
}
func main(){
my_func(nil) // sequential call
wg := sync.WaitGroup{}
wg.Add(1)
go my_func(&wg) // concurrent call
wg.Wait()
}
Is there any better way to achieve this ?
答案1
得分: 7
你的my_func()
不应该知道/关心它是如何执行的(无论是在新的goroutine中还是其他方式)。因此,你不应该传递wg
参数。不要强制要求并发或非并发使用你的API,让你的包的用户决定如何调用它。
如果有人希望并发地在新的goroutine中运行它,可以在my_func()
之外处理wg
,像这样:
wg.Add(1)
go func() {
defer wg.Done()
my_func()
}()
这样还可以在函数调用之前/之后执行其他代码,这些代码将在wg.Done()
调用之前执行:
wg.Add(1)
go func() {
defer wg.Done()
// 其他代码
my_func()
// 其他代码
}()
另外请注意,如果你在多个地方都有这样的代码,你可以创建一个辅助函数来处理goroutine的启动和waitgroup的处理:
func launchMyFunc(wg *sync.WaitGroup) {
go func() {
defer wg.Done()
my_func()
}()
}
你还可以创建一个接受任意无参数无返回值函数的辅助函数:
func launchFunc(wg *sync.WaitGroup, f func()) {
go func() {
defer wg.Done()
f()
}()
}
使用上述辅助函数,你可以这样做:
wg.Add(1)
launchMyFunc(wg)
// 或者
wg.Add(1)
launchFunc(wg, my_func)
英文:
Your my_func()
should not know / should not care how it is executed (whether in a new goroutine or not). So just for this you should not pass wg
. Do not enforce concurrent or non-concurrent use of your API, let users of your package decide how they wish to call it.
If someone wishes to run it concurrently, in a new goroutine, wg
can be handled outside of my_func()
like this:
wg.Add(1)
go func() {
defer wg.Done()
my_func()
}()
This also gives possibility to put further code before / after the function call that will be executed before the wg.Done()
call:
wg.Add(1)
go func() {
defer wg.Done()
// other code before
my_func()
// other code after
}()
Also note that if you have this in many places, you can create a helper function that takes care of the goroutine launching and waitgroup handling:
func launchMyFunc(wg *sync.WaitGroup) {
go func() {
defer wg.Done()
my_func()
}()
}
You can also create a helper that accepts an arbitrary no-arg no-return function:
func launchFunc(wg *sync.WaitGroup, f func()) {
go func() {
defer wg.Done()
f()
}()
}
Using the above helpers this is how you could do the same:
wg.Add(1)
launchMyFunc(wg)
// or
wg.Add(1)
launchFunc(wg, my_func)
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论