I want to execute 2 operations concurrently each one setting a variable (or returning a result)
The second goroutine will be executed conditionally.
In case the second one is not executed, the result set (or returned) by the second one is equal to the first one.
I am asking which is the optimal and most idiomatic way of going about this.
1. Litteral function invocation
var (
v1, v2 int
wg sync.WaitGroup
)
wg.Add(2)
go func(){
v1 = anotherfunc(param1)
wg.Done()
}
if something{
go func(){
v2 = anotherfunc(param2)
wg.Done()
}
} else {
v2 = v1
wg.Done()
}
wg.Wait()
2. Normal function invocation with channels
go anotherfunc(param1, channel1)
if something {
go anotherfunc(param2, channel2)
var2 <- channel2
}
var1 <- channel1
if !something {
var2 = var1
}
edit: I now realise the first approach has a flaw. We cannot guarantee that the first goroutine will have returned before the v2 = v1 assignment. Not sure if there is a way of keeping the first approach with some addition(s).
Anyway, I think this general approach is pretty readable / nice. However, I wonder if you could use channels and always just send two values so the main function doesn’t care how it gets the values as long as it gets them. Since you’re running your jobs sequentially, you only need one goroutine:
func main() {
var v1, v2 int
results := make(chan int)
go func() {
result := longRunning()
results <- result
// We need to do some additional processing to determine second value
if result > 50 {
result = longRunning()
}
// Send second value
results <- result
}()
v1 = <-results
fmt.Println("First:", v1)
v2 = <-results
fmt.Println("Second:", v2)
}
That seems pretty clean to me. Of course you need to be really careful about error handling and make sure that channel always sends two values.