I'm new to Go. When I comment out the second goroutine, there is a fatal error. I don't understand what causes this error to occur. Can you explain it to me?
package main
import (
"fmt"
"time"
)
func main() {
ch := make(chan int)
go func() {
for i := 0; i < 10; i++ {
ch <- i
}
} ()
// go func() {
for {
if num, ok := <-ch; !ok {
break
} else {
fmt.Printf("%d\n", num)
}
}
// } ()
time.Sleep(2 * time.Second)
close(ch)
}
This prints the following code:
0
1
2
3
4
5
6
7
8
9
fatal error: all goroutines are asleep - deadlock!
goroutine 1 [chan receive]:
main.main()
/tmp/sandbox169127128/main.go:17 +0xa0
Program exited.
The receiving for loop blocks on receive from ch after receiving all values from the sending goroutine. The runtime detects that the program is stuck and panics.
The fix is to close the channel after sending all values:
go func() {
for i := 0; i < 10; i++ {
ch <- i
}
close(ch)
} ()
Receive on the closed channel yields the value 0, false. The receiving for loop breaks on the false value.
Remove close(ch) from the end of the program.
Run it on the playground.
Because you're not closing the channel before the first goroutine exits. The below code should work.
package main
import (
"fmt"
"time"
)
func main() {
ch := make(chan int)
go func() {
for i := 0; i < 10; i++ {
ch <- i
}
close(ch)
} ()
//go func() {
for {
if num, ok := <-ch; !ok {
break
} else {
fmt.Printf("%d\n", num)
}
}
//} ()
time.Sleep(2 * time.Second)
}
Try it out here: https://play.golang.org/p/OdxNqbaZmj
Related
I am studying goroutines and channels. I wrote a practice code to figure out the concurrency problem of goroutine and solve it. Deposit() is called 10 times, passing a bool to the done channel. After that, this is the code that resolves the concurrency while receiving done.
I am getting an error when I run the following code:
package main
import (
"bank"
"fmt"
"log"
"time"
)
func main() {
start := time.Now()
done := make(chan bool)
// Alice
for i := 0; i < 10; i++ {
go func() {
bank.Deposit(1)
done <- true
}()
}
// Wait for both transactions.
for flag := range done {
if !flag {
panic("error")
}
}
fmt.Printf("Balance = %d\n", bank.Balance())
defer log.Printf("[time] Elipsed Time: %s", time.Since(start))
}
package bank
var deposits = make(chan int) // send amount to deposit
var balances = make(chan int) // receive balance
func Deposit(amount int) { deposits <- amount }
func Balance() int { return <-balances }
func teller() {
var balance int // balance is confined to teller goroutine
for {
select {
case amount := <-deposits:
balance += amount
case balances <- balance:
}
}
}
func init() {
go teller() // start the monitor goroutine
}
But I get an error.
fatal error: all goroutines are asleep - deadlock!
goroutine 1 [chan receive]:
main.main()
/Users/kyounghwan.choi/go/main.go:48 +0xd6
goroutine 49 [select]:
bank.teller()
/usr/local/go/src/bank/bank.go:14 +0x85
created by bank.init.0
/usr/local/go/src/bank/bank.go:23 +0x25
exit status 2
am i missing something?
what's the problem?
The deadlock occurs because the runtime detected that the remaining routines were stuck and could never proceed further.
That has happen because the implementation does not provide the required logic to exit the loop iteration over the done channel.
To exit that iteration the implementation must close the channel or break out.
This is commonly solved using a WaitGroup.
A WaitGroup waits for a collection of goroutines to finish. The main goroutine calls Add to set the number of goroutines to wait for. Then each of the goroutines runs and calls Done when finished. At the same time, Wait can be used to block until all goroutines have finished.
A WaitGroup must not be copied after first use.
func main() {
start := time.Now()
done := make(chan bool)
var wg sync.WaitGroup
for i := 0; i < 10; i++ {
wg.Add(1)
go func() {
defer wg.Done()
bank.Deposit(1)
done <- true
}()
}
go func() {
wg.Wait()
close(done)
}()
// Wait for the channel to close.
for flag := range done {
if !flag {
panic("error")
}
}
fmt.Printf("Balance = %d\n", bank.Balance())
defer log.Printf("[time] Elipsed Time: %s", time.Since(start))
}
https://go.dev/play/p/pyuguc6LaEX
Though, closing the channel, in this convoluted example, is really just a burden without additional values.
This main function could be written,
func main() {
start := time.Now()
var wg sync.WaitGroup
for i := 0; i < 10; i++ {
wg.Add(1)
go func() {
defer wg.Done()
bank.Deposit(1)
}()
}
wg.Wait()
fmt.Printf("Balance = %d\n", bank.Balance())
defer log.Printf("[time] Elipsed Time: %s", time.Since(start))
}
https://go.dev/play/p/U4Zh62Rt_Be
Though, it appears to me that removing the "concurrency" just works as good https://go.dev/play/p/qXs2oqi_1Zw
Using channels it is also possible to read at most as many times it was written.
func main() {
start := time.Now()
done := make(chan bool)
// Alice
for i := 0; i < 10; i++ {
go func() {
bank.Deposit(1)
done <- true
}()
}
// Read that much writes.
for i := 0; i < 10; i++ {
if !<-done {
panic("error")
}
}
fmt.Printf("Balance = %d\n", bank.Balance())
defer log.Printf("[time] Elipsed Time: %s", time.Since(start))
}
Change the following code blocks,
for i := 0; i < 10; i++ {
go func() {
bank.Deposit(1)
done <- true
}()
}
into
go func() {
for i := 0; i < 10; i++ {
bank.Deposit(1)
done <- true
}
close(done)
}()
Note: you need to explicitly close the channel.
I'm trying launch goroutines in an infinite loop until I get the response I'm looking for but the select is unreachable if I change for i := 0; i < 10; i++ {} to for {}. What's a pattern for solving this?
package main
import (
"fmt"
"math/rand"
"time"
)
func myFunc() float64 {
c := make(chan float64)
for i := 0; i < 10; i++ {
go func() {
var value float64
value = someOp()
if value > .9 {
c <- value
}
}()
}
// unreachable code the if the for loop above is infinite
for {
select {
case x := <-c:
return x
default:
}
}
}
func someOp() float64 {
rand.Seed(time.Now().UnixNano())
return rand.Float64()
}
func main() {
fmt.Println(myFunc())
}
Starting an unlimited number of goroutines is usually not a good idea. A better approach is to start a fixed number of goroutines that loop looking for an answer. Return from these goroutines when an answer is found.
func myFunc() float64 {
c := make(chan float64, 1) // Size 1 prevents race between main goroutine and workers
done := make(chan struct{})
defer close(done)
// Start a fixed number of goroutines
for i := 0; i < 10; i++ {
go func() {
for {
select {
case <-done:
// myfunc exited with result, return from this goroutine
return
default:
var value float64
value = someOp()
if value > .9 {
select {
case c <- value:
// This is first goroutine to send a value
default:
// Another goroutine sent a value
}
return
}
}
}
}()
}
return <-c
}
https://play.golang.org/p/SRpeT8k34eA
I'm trying to use a for loop that continuously sends strings to different channels read by different goroutines. However, it gives me the error "all goroutines are asleep - deadlock!" Why is this happening? I searched for some answers, but I couldn't find an answer for this situation.
func main() {
var chans []chan string
for i := 0; i < 3; i++ {
chans = append(chans, make(chan string))
}
for i := 0; i < 3; i++ {
go sendString(chans[i])
}
for str := range chans[0] {
fmt.Print(str)
}
}
func sendString(ch chan string) {
ch <- "a"
ch <- "b"
ch <- "c"
ch <- "d"
}
The errors are here. It prints "abcd", then generates the error, and if I delete the loop for printing, the program does not generate the error.
abcdfatal error: all goroutines are asleep - deadlock!
goroutine 1 [chan receive]:
main.main()
C:/Users/YuanZheng Hu/Desktop/Go Test/test/test.go:18 +0x28d
goroutine 19 [chan send]:
main.sendString(0xc04203c120)
C:/Users/YuanZheng Hu/Desktop/Go Test/test/test.go:24 +0x42
created by main.main
C:/Users/YuanZheng Hu/Desktop/Go Test/test/test.go:15 +0x175
goroutine 20 [chan send]:
main.sendString(0xc04203c180)
C:/Users/YuanZheng Hu/Desktop/Go Test/test/test.go:24 +0x42
created by main.main
C:/Users/YuanZheng Hu/Desktop/Go Test/test/test.go:15 +0x175
exit status 2
I did the version using WaitGroup, but it seems not correct, and gives me the same error " all goroutines are asleep - deadlock!" where did I do wrong in the code below ?
func main() {
var myWaitGroup sync.WaitGroup
ch := make(chan string)
myWaitGroup.Add(1)
go sendString(ch, &myWaitGroup)
myWaitGroup.Wait()
close(ch)
time.Sleep(1 * time.Second)
}
func sendString(ch chan string, pg *sync.WaitGroup) {
ch <- "a"
ch <- "b"
ch <- "c"
ch <- "d"
defer pg.Done()
}
The second for loop will block until the channel is closed so you need to close it in the sending function. Also, you only read from the first channel so some of the data is lost. Doing this:
func main() {
var chans []chan string
for i := 0; i < 3; i++ {
chans = append(chans, make(chan string))
}
for i := 0; i < 3; i++ {
go sendString(chans[i])
}
for i := 0; i < 3; i++ {
for str := range chans[i] {
fmt.Print(str)
}
}
}
func sendString(ch chan string) {
ch <- "a"
ch <- "b"
ch <- "c"
ch <- "d"
close(ch)
}
Will produce:
abcdabcdabcd
https://play.golang.org/p/7SoDKChnTbz
If you wanted to do this with a single channel as per your comment then you could add a wait group to close the channel once all the go routines are complete:
func main() {
c := make(chan string)
var wg sync.WaitGroup
for i := 0; i < 3; i++ {
wg.Add(1)
go func() {
sendString(c)
wg.Done()
}()
}
go func() {
wg.Wait()
close(c)
}()
for str := range c {
fmt.Print(str)
}
}
func sendString(ch chan string) {
ch <- "a"
ch <- "b"
ch <- "c"
ch <- "d"
}
https://play.golang.org/p/E_awt8UBK9v
How do i block the the main func and allow goroutines communicate through channels the following code sample throws me an error
0fatal error: all goroutines are asleep - deadlock!
package main
import (
"fmt"
"time"
)
func main() {
ch := make(chan int)
go func() {
value := <-ch
fmt.Print(value) // This never prints!
}()
go func() {
for i := 0; i < 100; i++ {
time.Sleep(100 * time.Millisecond)
ch <- i
}
}()
c := make(chan int)
<-c
}
I think you want to print all value [0:99]. Then you need loop in 1st go routine.
And also, you need to pass signal to break loop
func main() {
ch := make(chan int)
stopProgram := make(chan bool)
go func() {
for i := 0; i < 100; i++ {
value := <-ch
fmt.Println(value)
}
// Send signal through stopProgram to stop loop
stopProgram <- true
}()
go func() {
for i := 0; i < 100; i++ {
time.Sleep(100 * time.Millisecond)
ch <- i
}
}()
// your problem will wait here until it get stop signal through channel
<-stopProgram
}
why in that script http://play.golang.org/p/Q5VMfVB67-
goroutine shower doesn't work ?
package main
import "fmt"
func main() {
ch := make(chan int)
go producer(ch)
go shower(ch)
for i := 0; i < 10; i++ {
fmt.Printf("main: %d\n", i)
}
}
func shower(c chan int) {
for {
j := <-c
fmt.Printf("worker: %d\n", j)
}
}
func producer(c chan int) {
for i := 0; i < 10; i++ {
c <- i
}
}
Your main function exit way before the goroutines have a chance to complete their own work.
You need to wait for them to finish before ending main() (which stops the all program), with for instance sync.WaitGroup, as seen in "Wait for the termination of n goroutines".
In your case, you need to wait for goroutine shower() to end: pass a wg *sync.WaitGroup instance, for shower() to signal wg.Done() when it finishes processing.