If I have 3 function calls inside of `main` and place a bunch of goroutines inside of the middle (2nd) function call, will 2nd fn block the third? - go

I'm trying to run a handful of goroutines within an anon function and have that anon function run sequentially with the rest of main.
Is this possible in go?
What I've tried:
func main() {
wg := new(sync.WaitGroup)
wg.Add(4)
fmt.Println("hello")
func() {
go func() {
defer wg.Done()
fmt.Println(1)
}()
go func() {
defer wg.Done()
fmt.Println(2)
}()
go func() {
defer wg.Done()
fmt.Println(3)
}()
go func() {
defer wg.Done()
fmt.Println(4)
}()
}()
fmt.Println("goodbye")
wg.Wait()
}
Which outputted:
"hello"
"goodbye"
// in a random order
1
2
3
4
Desired output:
"hello"
// in any order
1
2
3
4
"goodbye"

Related

sync.WaitGroup deadlock caused by pass by value?

There's 2 ways to write the repro:
The 1st way, the program exits clean.
func recurse(depth int, wg *sync.WaitGroup) {
defer wg.Done()
if depth == 0 {
return
}
wg.Add(1)
go recurse(depth - 1, wg)
}
func main() {
wg := sync.WaitGroup{}
wg.Add(1)
go recurse(3, &wg)
wg.Wait()
}
The 2nd way, the program gives "fatal error: all goroutines are asleep - deadlock!"
func recurse(depth int, wg sync.WaitGroup) {
defer wg.Done()
if depth == 0 {
return
}
wg.Add(1)
go recurse(depth - 1, wg)
}
func main() {
var wg sync.WaitGroup
wg.Add(1)
go recurse(3, wg)
wg.Wait()
}
Would anyone kindly explain the intricate way in which the 2nd way differs from the 1st way so as to cause "Deadlock"?
WaitGroup under the hood is just a struct containing a counter guarded by mutex. Go provide arguments to functions copy_by_value way. So recurse( depth, wg) function receive only a copy of counter when passed by value. Like this:
counter := 5
func(counter){
counter--
fmt.Println(counter) //will print "4"
}(counter)
fmt.Println(counter) //will be "5" again

Go, passing data to channel

I have an issue. Here is example: https://play.golang.org/p/QSWY2INQuSE
func Avg(c chan string, wg *sync.WaitGroup) {
defer wg.Done()
c <- "test"
}
func main() {
var wg sync.WaitGroup
c := make(chan string)
timer1 := time.NewTicker(5 * time.Second)
for {
select {
case <-timer1.C:
wg.Add(1)
go Avg(c, &wg)
wg.Wait()
}
}
fmt.Println(<-c)
}
Why data does not reach fmt.Println(<-c)
Thank you!
Because you have an endless for, so the last fmt.Println() statement is never reached.
You have to break out of the loop if you want the last fmt.Println() statement to ever execute, for example:
loop:
for {
select {
case <-timer1.C:
wg.Add(1)
go Avg(c, &wg)
wg.Wait()
break loop
}
}
fmt.Println(<-c)
Note that you have to use a label, else the break would only break out of the select statement (and not from the for loop).
Also note that this alone won't work, as the channel is unbuffered, and thus Avg() will be blocked forever, trying to send a value on c while noone is ever trying to receive from it.
This simple example can be made working if you create the channel to be buffered:
c := make(chan string, 1) // Buffer for 1 value
Now it works and prints (try it on the Go Playground):
test

WaitGroup goroutines with channel

I am learning WaitGroup from the blog https://nathanleclaire.com/blog/2014/02/15/how-to-wait-for-all-goroutines-to-finish-executing-before-continuing/
the code:
package main
import (
"fmt"
"sync"
"time"
)
func main() {
messages := make(chan int)
var wg sync.WaitGroup
// you can also add these one at
// a time if you need to
wg.Add(3)
go func() {
defer wg.Done()
time.Sleep(time.Second * 3)
messages <- 1
}()
go func() {
defer wg.Done()
time.Sleep(time.Second * 2)
messages <- 2
}()
go func() {
defer wg.Done()
time.Sleep(time.Second * 1)
messages <- 3
}()
go func() {
for i := range messages {
fmt.Println(i)
}
}()
wg.Wait()
}
I think it should print 3, 2 and 1 in order. But it only prints 3, 2 but 1 is missing, what's the problem?
You can tree it on https://play.golang.org/p/kZCvDhykYM
Right after the latest messages <- 1, the deferred wg.Done() is invoked which releases wg.Wait() in the end of the program and the program quits. When a program quits all the goroutines get killed, so the printing goroutine does not have a chance to print the latest value.
If you put something like time.Sleep(time.Second * 1) right after wg.Done() you would be able to see all the output lines.
package main
import (
"fmt"
"sync"
"time"
)
func main() {
messages := make(chan int)
var wg sync.WaitGroup
wg.Add(3)
// created this goroutine to wait for other
// goroutines to complete and to close the channel
go func() {
wg.Wait()
close(messages)
}()
go func() {
defer wg.Done()
time.Sleep(time.Second * 3)
messages <- 1
}()
go func() {
defer wg.Done()
time.Sleep(time.Second * 2)
messages <- 2
}()
go func() {
defer wg.Done()
time.Sleep(time.Second * 1)
messages <- 3
}()
// this for loop is blocked in main goroutine.
// till it reads all messages and channel is closed.
for v := range messages {
fmt.Print(v)
}
}
The mentioned blog starts with following comment:
EDIT: As pointed out by effenn in this Reddit comment, a lot of information in this article is “dangerously inaccurate”. OOPS! I’ve written a followup/correction article here for your viewing pleasure, but I’m leaving this article up for “historical purposes”.
The Reddit comment and the followup article both describe the problem and give a solution to your problem. (Adding time.Sleep(...) to make the program work the way you expect is really hacky...)
package main
import (
"fmt"
"sync"
"time"
)
func main() {
messages := make(chan int)
var wg sync.WaitGroup
// you can also add these one at
// a time if you need to
wg.Add(3)
go func() {
defer wg.Done()
time.Sleep(time.Second * 3)
messages <- 1
}()
go func() {
defer wg.Done()
time.Sleep(time.Second * 2)
messages <- 2
}()
go func() {
defer wg.Done()
time.Sleep(time.Second * 1)
messages <- 3
}()
exit:
for {
select {
case i, ok := <-messages:
if !ok {
break exit
}
fmt.Println(i)
default:
time.Sleep(time.Second)
}
}
wg.Wait()
}

GoRoutines, Channels with WaitGroup unexpected output

I looked at some code that I've wrote a long time ago, when go1.3 was released(I might be wrong). CODE HERE
The below code used to work as expected, but now since I've update go to the current master version(go version devel +bd1efd5 Fri Jul 31 16:11:21 2015 +0000 darwin/amd64), the last output message c <- "FUNC 1 DONE" is not printed, the code works as it should on play.golang.org. Did I do something wrong, or this is a bug?
package main
import ("fmt";"sync";"time")
func test(c chan string, wg *sync.WaitGroup) {
defer wg.Done()
fmt.Println("EXEC FUNC 1")
time.Sleep(3 * time.Second)
c <- "FUNC 1 DONE"
}
func test1(c chan string, wg *sync.WaitGroup) {
defer wg.Done()
fmt.Println("EXEC FUNC 2")
time.Sleep(2 * time.Second)
c <- "FUNC 2 DONE"
}
func main() {
ch := make(chan string)
var wg sync.WaitGroup
wg.Add(2)
go test(ch, &wg)
go test1(ch, &wg)
go func(c chan string) {
for txt := range c {
fmt.Println(txt)
}
}(ch)
wg.Wait()
}
UPDATE:
I'm not saying that, the above is the best way of doing those types of work, but I don't see anything wrong with it.
Also running it in go version go1.4.2 darwin/amd64 will return the expected output.
Your code has always had this bug. It was only by chance that your program managed to print all messages before main exited.
To make this work correctly, I would invert where you have the wg.Wait() and the channel receives, so you can asynchronously close the channel. This way the receive operations are what is blocking main, and the channel is closed as soon as all send operations are done.
func main() {
ch := make(chan string)
var wg sync.WaitGroup
wg.Add(2)
go test(ch, &wg)
go test1(ch, &wg)
go func() {
wg.Wait()
close(ch)
}()
for txt := range ch {
fmt.Println(txt)
}
}

Go WaitGroup with goroutine

I wonder why we need to run the wg.Wait() in goroutine
// This one works as expected...
func main() {
var wg sync.WaitGroup
for i:=0; i<5; i++ {
wg.Add(1)
go func() {
defer wg.Done()
}()
time.Sleep(time.Second)
}
go func() {
wg.Wait()
}()
}
But this one never ends waiting forever
func main() {
var wg sync.WaitGroup
for i:=0; i<5; i++ {
wg.Add(1)
go func() {
defer wg.Done()
}()
time.Sleep(time.Second)
}
wg.Wait()
}
Can anybody explain why I need to wait in another goroutine?
Thanks!
why we need to run the wg.Wait() in goroutine?
In the example you mention (coop/blob/master/coop.go#L85), the wait is in a goroutine in order to return immediately a channel that will indicate when all the other goroutines have completed.
Those are the goroutines to be started:
for _, fn := range fns {
go func(f func()) {
f()
wg.Done()
}(fn)
}
They mention the completion through the var wg sync.WaitGroup.
That WaitGroup is set to wait for the right number of goroutines to finish:
wg.Add(len(fns))
The wait is done in a goroutine because it will in turn signal the global completion to a channel:
go func() {
wg.Wait()
doneSig(ch, true)
}()
But the channel is returned immediately.
ch := make(chan bool, 1)
...
return ch
That is why the Wait is done asynchronously: you don't want to wait in this function. You just want the channel.

Resources