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 ?
CodePudding user response:
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)