I am learning channels in Go by following this tutorial.
When I only send value to a channel it gives error. Here is the example code.
package main
import "fmt"
func main() {
ch := make(chan int)
ch <- 1
fmt.Println("Does not work")
}
Here I am just sending value to the channel but not receiving anything. It give an error
fatal error: all goroutines are asleep - deadlock!
But when I run following code it doesn't give any error
package main
import "fmt"
func sum(s []int, c chan int) {
sum := 0
for _, v := range s {
sum += v
}
c <- sum // send sum to c
}
func main() {
s := []int{7, 2, 8, -9, 4, 0}
c := make(chan int)
go sum(s[:len(s)/2], c)
go sum(s[len(s)/2:], c)
fmt.Println("did not receive but still works")
}
and prints
did not receive but still works
I couldn't understand why it works in second case while it does not work in first case. Even though I have not received any value for the channel in both cases. Also what is causing the deadlock in first case and how it gets avoided in second case?
Neither example works. In fact, no example that only sends to a channel will ever work, in any traditional sense of "work".
But here's a step through of each, to make it clear:
First example
ch := make(chan int)
This creates an unbuffered channel. Unbuffered channels don't hold any data, they only act as a conduit for communication--all data sent must be received by something else, before the program execution proceeds--on either side of the channel.
ch <- 1
Here you send data on the channel, but nothing is waiting to receive it, so the program waits. In this case, it waits forever, because you never created a receiver for the channel, thus your deadlock.
Second example
c := make(chan int)
Again, create an unbuffered channel.
go sum(s[:len(s)/2], c)
Call the sum function, which, incidentally, will also block forever, for the reasons described above--nothing is receiving on the channel, so it will wait forever. However, in this case, you've called it in a goroutine. The goroutine will run in a separate execution thread, while other bits of the program run. Although, due to never receiving data from the channel, this goroutine will never exit, until the main program exits.
go sum(s[len(s)/2:], c)
Again, you call sum, and again, in a goroutine. So at this point, you have three gorotuines: One running main(), and one each running an invocation of sum(). The latter two will never exit.
Then your program exits. When the program exits, all goroutines (including the two that are stuck forever waiting on your channel) exit.
Since this program exits immediately, the deadlock is never reported, but it does assuredly exist, same as in your first example.
Related
package main
import (
"fmt"
"math/rand"
"time"
)
func boring(msg string) <-chan string { // Returns receive-only channel of strings.
c := make(chan string)
go func() { // We launch the goroutine from inside the function.
for i := 0; ; i++ {
c <- fmt.Sprintf("%s %d", msg, i)
time.Sleep(time.Duration(rand.Intn(1e3)) * time.Millisecond)
}
}()
return c // Return the channel to the caller.
}
func fanIn(input1, input2 <-chan string) <-chan string {
c := make(chan string)
go func() {
for {
c <- <-input1
}
}()
go func() {
for {
c <- <-input2
}
}()
return c
}
func main() {
c := fanIn(boring("Joe"), boring("Ann"))
for i := 0; i < 10; i++ {
fmt.Println(<-c)
}
fmt.Println("You're both boring; I'm leaving.")
}
This is an example from Rob Pike's talk on Go Concurrency Patterns. I understand the idea behind the fan-in pattern and I understand that the order of messages printed in main is non-deterministic: we just print 10 messages that turn out to be ready.
What I do not completely understand, however, is the order of calls and what blocks what.
Only unbuffered channels are used so, as per the documentation, an unbuffered channel blocks the sender.
The boring function launches a goroutine that sends strings to the unbuffered channel c, which is returned. If I understand correctly, this inner goroutine is launched but doesn't block boring. It can immediately return the channel in main to the fanIn function. But fanIn does almost the same thing: it receives the values from the input channel and sends them to its own channel that is returned.
How does the blocking happen? What blocks what in this case? A schematic explanation would be perfect because, honestly, even though I have an intuitive understanding, I would like to understand the exact logic behind it.
My intuitive understanding is that each send inside boring blocks until the value is received in fanIn, but then the value is immediately sent to another channel so it gets blocked until the value is received in main. Roughly speaking, the three functions are tightly bound to each other due to the use of channels
How does the blocking happen? What blocks what in this case?
Each send on an unbuffered channel blocks if there is no corresponding receive operation on the other side (or if the channel is nil, which becomes a case of having no receiver).
Consider that in main the calls to boring and fanIn happen sequentially. In particular this line:
c := fanIn(boring("Joe"), boring("Ann"))
has order of evaluation:
boring("Joe")
boring("Ann")
fanIn
The send operations in boring("Joe") and boring("Ann") have a corresponding receive operation in fanIn, so they would block until fanIn runs. Hence boring spawns its own goroutine to ensure it returns the channel before fanIn can start receiving on it.
The send operations in fanIn have then a corresponding receive operation in main, so they would block until fmt.Println(<-c) runs. Hence fanIn spawns its own goroutine(s) to ensure it returns the out channel before main can start receiving on it.
Finally main's execution gets to fmt.Println(<-c) and sets everything in motion. Receiving on c unblocks c <- <-input[1|2], and receiving on <-input[1|2] unblocks c <- fmt.Sprintf("%s %d", msg, i).
If you remove the receive operation in main, main can still proceed execution and the program exits right away, so no deadlock occurs.
I'm not understanding why this doesn't work https://play.golang.org/p/_ALPii0pXV6 but this https://play.golang.org/p/vCOjAr-o54e works.
As I understand the goroutine asynchronously sends to value true to a and 12 to b. While in the main function, a is blocked, until it receives a value. Why is it that when I rearrange it to have b is blocked before a, it results in a deadlock?
Go channels are unbuffered by default. That means that it cannot send on a channel until the receiver is reading the channel. This is actually the Go preferred mode. It's more efficient than buffered channels in most cases.
What that means for your first code is that the goroutine cannot proceed to write to channel b until it completes the write to channel a. It cannot do that until the main goroutine reads a.
Go by Example explains that, by default, channel sending and receiving waits until both the sending routine and the receiving routine are ready. This blocking is made obvious by the following example:
func main() {
ch := make(chan int)
ch <- 1
fmt.Println(<-ch)
}
This code results in a deadlock because the only goroutine (the main one) is stuck at ch <- 1, waiting for another goroutine to receive. Little does it know that we are expecting it to be the receiver at the next line.
This explains why your first example does not work, because the other goroutine doesn't send on b until its send operation on a has completed. But the main routine won't receive on a until it's received on b! So both are stuck waiting forever.
To read more about this kind of operation (called a synchronous operation), check out this explanation.
If you rewrite the code the way it is going to be executed sequentially then it becomes clearer what's going on.
Original code:
func main() {
a := make(chan bool)
b := make(chan int64)
go func(a chan bool, b chan int64) {
fmt.Println("Here1")
a <- true
b <- 12
} (a,b)
fmt.Println("Here2")
fmt.Println(fmt.Sprintf("%d", <-b))
fmt.Println(fmt.Sprintf("%v", <-a))
}
Close representation of sequential execution of the same code:
a := make(chan bool)
b := make(chan int64)
fmt.Println("Here2") // Prints
// Pass control to new goroutine
fmt.Println("Here1")
a <- true // Write to channel a and block goroutine here and pass control to main
fmt.Println(fmt.Sprintf("%d", <-b)) // Tries to read from b but nothing has been written to it so blocks. At this point all your goroutines are blocked hence the deadlock.
fmt.Println(fmt.Sprintf("%v", <-a)) // doesn't even reach here.
b <- 12
}
The following code runs perfectly fine:
package main
import (
"fmt"
)
func my_func(c chan int){
fmt.Println(<-c)
}
func main(){
c := make(chan int)
go my_func(c)
c<-3
}
playgound_1
However if I change
c<-3
to
time.Sleep(time.Second)
c<-3
playground_2
My code does not execute.
My gut feeling is that somehow main returns before the my_func finishes executing, but it seems like adding a pause should not have any effect. I am totally lost on this simple example, what's going on here?
When the main function ends, the program ends with it. It does not wait for other goroutines to finish.
Quoting from the Go Language Specification: Program Execution:
Program execution begins by initializing the main package and then invoking the function main. When that function invocation returns, the program exits. It does not wait for other (non-main) goroutines to complete.
So simply when your main function succeeds by sending the value on the channel, the program might terminate immediately, before the other goroutine has the chance to print the received value to the console.
If you want to make sure the value gets printed to the console, you have to synchronize it with the event of exiting from the main function:
Example with a "done" channel (try it on Go Playground):
func my_func(c, done chan int) {
fmt.Println(<-c)
done <- 1
}
func main() {
c := make(chan int)
done := make(chan int)
go my_func(c, done)
time.Sleep(time.Second)
c <- 3
<-done
}
Since done is also an unbuffered channel, receiving from it at the end of the main function must wait the sending of a value on the done channel, which happens after the value sent on channel c has been received and printed to the console.
Explanation for the seemingly non-deterministic runs:
Goroutines may or may not be executed parallel at the same time. Synchronization ensures that certain events happen before other events. That is the only guarantee you get, and the only thing you should rely on.
2 examples of this Happens Before:
The go statement that starts a new goroutine happens before the goroutine's execution begins.
A send on a channel happens before the corresponding receive from that channel completes.
For more details read The Go Memory Model.
Back to your example:
A receive from an unbuffered channel happens before the send on that channel completes.
So the only guarantee you get is that the goroutine that runs my_func() will receive the value from channel c sent from main(). But once the value is received, the main function may continue but since there is no more statements after the send, it simply ends - along with the program. Whether the non-main goroutine will have time or chance to print it with fmt.Println() is not defined.
Environment: OS X 10.8, Go 1.0.2
I make a channel with buffer-size 2, then if I write channel three times, it will throw error:
throw: all goroutines are asleep - deadlock!
Of course, it's correct.
BUT if I write channel four or more times in the goroutines, it works fine, why?
The channel's capacity is 2, why goroutines ignore that or forget the capacity setting?
I comment the read-channel codes, so no one will read channel and save the capacity. I also use time.Sleep to waiting for all goroutines finish their work.
please review following codes:
package main
//import "fmt"
func main() {
c := make(chan int, 2)
/*c <- 1
c <- 2
c <- 3*/
for i:=0; i<4; i++ {
go func(i int) {
c <- i
c <- 9
c <- 9
c <- 9
}(i)
}
time.Sleep(2000 * time.Millisecond)
/*for i:=0; i<4*2; i++ {
fmt.Println(<-c)
}*/
}
Would anyone please give some hits? thanks, guys.
When a channel is buffered, this means it will not block until the buffer is full. Once the buffer is full, the sending goroutine will block as it tries to add things to the channel.
This means that this will block:
c := make(chan int)
c <- 1 // Block here, this is unbuffered !
println(<-c)
And this will also block:
c := make(chan int, 2)
c <- 1
c <- 2
c <- 3 // Block here, buffer is full !
println(<-c)
But the point of goroutines and channel is precisely to run things concurrently, so this will work:
c := make(chan int)
go func() { c <- 1; }() // This will block in the spawned goroutine until...
println(<-c) // ... this line is reached in the main goroutine
And similarly:
c := make(chan int, 2)
go func() { // `go ...` spawns a goroutine
c <- 1 // Buffer is not full, no block
c <- 2 // Buffer is not full, no block
c <- 3 // Buffer is full, spawned goroutine is blocking until...
}()
println(<-c) // ... this line is reached in the main goroutine
In your example, you spawn four different goroutines, which all write four numbers to the same buffered channel. As the buffer is 2 < 16, they will end up blocking
But the crux of the matter is that the Go policy is to wait only for the main goroutine:
Program execution begins by initializing the main package and then invoking the function main. When the function main returns, the program exits. It does not wait for other (non-main) goroutines to complete.
This means that in your first example, the main goroutine was blocking when it reached line c <- 3. As no other goroutine was able to do anything which could potentially unblock it, the runtime detected that the program was deadlocked and reported an error.
In your second example however, spawned goroutines block, while the main continues quietly until it reaches the end of its execution, at which point all the (blocked) spawned goroutines are silently killed, and no error is reported.
val has given a good answer. I'd like to add an extra tip I've found useful.
When learning to use goroutines, use zero-buffered channels to start with. This way, when you make a mistake, you'll immediately get a deadlock, which you can learn from. You need to learn how to write code that doesn't deadlock, which means learning tricks like not having cyclic dependencies in the client-server relationships (assuming your goroutines are written as clients or servers).
Reasoning about the network without buffering is simpler, although this might not be obvious at first.
Buffering is really useful, but should be considered as a means to enhance performance.
I'm trying to implement an Observer Pattern suggested here; Observer pattern in Go language
(the code listed above doesn't compile and is incomplete). Here, is a complete code that compiles but I get deadlock error.
package main
import (
"fmt"
)
type Publisher struct{
listeners []chan int
}
type Subscriber struct{
Channel chan int
Name string
}
func (p *Publisher) Sub(c chan int){
p.listeners = append(p.listeners, c)
}
func (p *Publisher) Pub(m int, quit chan int){
for _, c := range p.listeners{
c <- m
}
quit <- 0
}
func (s *Subscriber) ListenOnChannel(){
data := <-s.Channel
fmt.Printf("Name: %v; Data: %v\n", s.Name, data)
}
func main() {
quit := make(chan int)
p := &Publisher{}
subscribers := []*Subscriber{&Subscriber{Channel: make(chan int), Name: "1"}, &Subscriber{Channel: make(chan int), Name: "2"}, &Subscriber{Channel: make(chan int), Name: "3"}}
for _, v := range subscribers{
p.Sub(v.Channel)
go v.ListenOnChannel()
}
p.Pub(2, quit)
<-quit
}
Also, if I get rid of 'quit' completely, I get no error but it only prints first record.
The problem is that you're sending to quit on the same goroutine that's receiving from quit.
quit has a buffer size of 0, which means that in order to proceed there has to be a sender on one side and a receiver on the other at the same time. You're sending, but no one's on the other end, so you wait forever. In this particular case the Go runtime is able to detect the problem and panic.
The reason only the first value is printed when you remove quit is that your main goroutine is exiting before your remaining two are able to print.
Do not just increase channel buffer sizes to get rid of problems like this. It can help (although in this case it doesn't), but it only covers up the problem and doesn't truly fix the underlying cause. Increasing a channel's buffer size is strictly an optimization. In fact, it's usually better to develop with no buffer because it makes concurrency problems more obvious.
There are two ways to fix the problem:
Keep quit, but send 0 on it in each goroutine inside ListenOnChannel. In main, make sure you receive a value from each goroutine before moving on. (In this case, you'll wait for three values.)
Use a WaitGroup. There's a good example of how it works in the documentation.
In general this looks good, but there is one problem. Remember that channels are either buffered or unbuffered (synchronous or asynchronous). When you send to an unbuffered channel or to a channel with a full buffer the sender will block until the data has been removed from the channel by a receiver.
So with that, I'll ask a question or two of my own:
Is the quit channel synchronous or asynchronous?
What happens in Pub when execution hits quit<-0?
One solution that fixes your problem and allows the code to run is to change the second-to-last code line to be go p.Pub(2, quit). But there is another solution. Can you see what it is?
I don't actually get the same behavior you do if I remove <-quit from the original code. And this should not affect the output because as it is written that line is never executed.