I have tried to recreate a situation below, wherein I am trying to run three functions concurrently. However, I can only run the second and third function after a certain point in the first function, since it depends on a value from the first function. For this case, I used a channel. Here's my code:
package code
import "fmt"
func First(c chan string) {
for i := 0; i < 10000; i++ {
continue
}
test := "test"
fmt.Println(test)
c <- test
for i := 0; i < 10000; i++ {
fmt.Print(i)
}
}
func Second(c chan string) {
msg:= <- c
fmt.Println(msg)
if msg != "" { // I need to run the whole of First before running second and third concurrently then
fmt.Println("second", msg)
for i := 0; i < 10000; i++ {
fmt.Print(i)
}
}
}
func Third(c chan string) {
msg:= <- c
fmt.Println("third", msg)
for i := 0; i < 10000; i++ {
fmt.Print(i)
}
}
package main
import (
"./code"
"fmt"
"sync"
//"sync"
"time"
)
func main() {
start := time.Now()
var wg sync.WaitGroup
wg.Add(3)
var c chan string = make(chan string)
go func() {
code.First(c)
wg.Done()
}()
go func() {
code.Second(c)
wg.Done()
}()
go func() {
code.Third(c)
wg.Done()
}()
wg.Wait()
end := time.Now()
delta := end.Sub(start)
fmt.Println("time", delta.Seconds())
}
Currently, I am getting a deadlock. A couple extra questions- is there a way to first check the values given by the channel, and if they are not certain expected values I first complete running the first function and then run second and third concurrently? Essentially a check like the one I added in second? If it is the expected value I'd like all the functions to run concurrently after the channel gets particular values from the first function.
Your main program spawns off three extra goroutines, and then waits for all three to signal (via wg.Done
) that they are done. All three goroutines, plus main
itself, share one channel over which you can send one string
instance at a time (and which you use to send exactly one).
One goroutine (which calls code.First
) spins for a bit and then sends a string. Once the string is sent, that goroutine prints many numbers, then signals done-ness and quits.
Two other goroutines (which call code.Second
and code.Third
) immediately block waiting to receive a string. Depending on precisely when they run and the vagaries of who gets the string, one of them will get the string that code.First
sends. The other remains blocked.
Whichever one gets a string (which is currently always "test"
), that one then prints its name and many numbers, then signals done-ness and quits.
Whichever one didn't get a string is still waiting for a string. Meanwhile, the wg.Wait
in main
is waiting for the last wg.Done
call, which can no longer occur as all remaining goroutines are waiting (there are now just these two—main
and whichever didn't get the string—left). This is your deadlock.
It looks as though you expected both goroutines to receive the string that was sent from code.First
. That does not happen: one of them gets the string, and the other continues waiting. (There is no promise as to who gets the string.)
A couple extra questions- is there a way to first check the values given by the channel ...
Sure: whatever string you get, you have a string. You can do whatever operation you like with it, just as you already compare it to ""
.
... and if they are not certain expected values I first complete running the first function and then run second and third concurrently
That's just a Small Matter Of Programming. If you wish to be able to control who gets which message(s), though, you'll need one channel per receiving goroutine. If you make two separate channels, code.First
can take both, and can send an appropriate message to either additional goroutine at whatever point you like.