comparation about keyword "go" and without in Goroutine - go

The following code logged an error:
fatal error: all goroutines are asleep - deadlock!
package main
import "fmt"
func main() {
ch := make(chan int)
ch <- 1
fmt.Println(<-ch)
}
But when I changed the code into this:
package main
import "fmt"
func assign (ch chan int) {
ch <- 1
}
func main() {
ch := make(chan int)
go assign (ch)
fmt.Println(<-ch)
}
"1" was printed out.
Then I used buffered channels:
package main
import "fmt"
func main() {
ch := make(chan int, 2)
ch <- 1
ch <- 2
fmt.Println(<-ch)
fmt.Println(<-ch)
}
"1" and "2" can also be printed out.
I'm a little confused about the situation. Thanks in advance!

Why the deadlock happened:
In the first code snippet you have only one main goroutine and it is blocked when you are trying to write into the channel here:
ch <- 1
Because nobody reads from the channel and the main goroutine is waiting for this to continue.
See Effective Go -> Channels
If the channel is unbuffered, the sender blocks until the receiver has received the value.
The sender is main function, the receiver is also main function.
How to avoid the deadlock:
In order to solve this, you have two options:
Option 1: make the ch channel buffered like this:
ch := make(chan int, 1) // buffer length is set to 1
From A Tour of Go
Sends to a buffered channel block only when the buffer is full.
So, you can write to the channel until the buffer is full. Then somebody has to start reading from the channel.
Option 2: write to the channel from a goroutine, like you did in the second code snippet:
func assign(ch chan int) {
ch <- 1
}
func main() {
ch := make(chan int)
go assign(ch) // does not block the main goroutine
fmt.Println(<-ch) // waiting to read from the channel
}
In this case main function will be executed until fmt.Println(<-ch) and continues as soon as it can read from the channel.

When you are using unbuffered channel, goroutine is blocked during write until someone does the read.
In your first snippet, there is an unbuffered channel and single goroutine (main goroutine).
So when you are trying to write:
ch <- 1
Nobody reads from the channel yet. The main goroutine is blocked and this line is never executed:
fmt.Println(<-ch)
That's why you've got the deadlock error.
In the second example, you still using unbuffered channel, which means write operation blocks the goroutine.
But by using go you are running the second goroutine.
It means even if this new goroutine will be blocked during write (in your assign function), the main goroutine will continue to work and fmt.Println(<-ch) will be executed and do the read (which in turn unblock background goroutine and assign function will finally reach the end).
To get more understanding about channels and goroutines, this snippet will give the same result (as your second snippet):
package main
import "fmt"
func print(ch chan int) {
fmt.Println(<-ch)
}
func main() {
ch := make(chan int)
go print(ch)
ch <- 1
}
When you are working with a buffered channel (third snippet), you can do N write operations without blocking goroutine (where N is the size of the buffer).
That's why in your example you did 2 writes without blocking and is able to read them later. But if your buffer is less than the count of write operations, and nobody do the read, you will fall into the same blocking issues (see the explanation of 1&2 snippets).

Related

Why the program blocks by the channel in the select?

package main
import (
"fmt"
)
type A struct{
exit chan bool
}
func (a *A) f(){
select{
//the routine process
//quit
case <- a.exit:
fmt.Println("-----over-----")
a.exit <- true
fmt.Println("+++++over++++++")
}
}
func main() {
a := A{}
go a.f()
a.exit = make(chan bool)
a.exit <- true
}
I'd like to run muti goroutines,and I want let the main func to notice other goroutine to quit.
here is my code,but the program block in the select,the program only output "-----over-----",without "+++++over++++++",what's wrong with the code?Grateful for your help.
Your program blocks because that is what you have written, consider this order of operations:
main goroutine starts a.f goroutine.
a.f blocks trying to read from the nil channel a.exit.
main sets a.exit to be an unbuffered channel, a.f is now blocked reading from the new channel, this is allowed.
main writes a value into a.exit and a.f reads the value from a.exit, this synchronises the goroutines, nether are blocked now.
a.f now blocks trying to write into the unbuffered a.exit, this will never unblock because nobody will ever try to read from the channel again.
main now exits and causes all other goroutines to exit, this might happen before step 5.
So the reasons your program never outputs +++++over++++++ are:
Your a.f goroutine blocks at a.exit <- true because no other goroutine will read this value from the channel.
Your main goroutine will probably exit and terminate the entire program before a.f can finish working.
I think you are asking how to make main exit after the goroutine is finished, this is the most simple example of that:
package main
import (
"fmt"
)
type A struct {
exit chan struct{}
}
func (a *A) f() {
defer close(a.exit) // Close the chanel after f() finishes, closed channels yield the zero-value so <-a.exit will unblock
fmt.Println("+++++over++++++")
}
func main() {
a := A{}
go a.f()
a.exit = make(chan struct{})
<-a.exit
}

Can't read from a channel in goroutine [duplicate]

This question already has answers here:
No output from goroutine
(3 answers)
Closed 3 years ago.
In this piece of code, a goroutine is created and tries to read from a buffered channel.
But the buffer is empty and should block the receiver, but it didn't. It will run but output nothin.
package main
import "fmt"
func fun(c chan int) {
fmt.Println(<-c)
}
func main() {
ch := make(chan int, 1)
//ch <- 1
go fun(ch)
}
First, the buffer is not empty, because you send a value on it:
ch <- 1
This send operation will not block because the channel is buffered.
Then you launch a goroutine, and the main() function ends. And with that, your program ends as well, it does not wait for other non-main goroutines to complete. For details, see No output from goroutine in Go.
Note that the same thing happens even if you comment out the send operation in main(): you launch a goroutine and then main() ends along with your app: it does not wait for the other goroutine.
To wait for other goroutines, often a sync.WaitGroup is used like this:
var wg = &sync.WaitGroup{}
func fun(c chan int) {
defer wg.Done()
fmt.Println(<-c)
}
func main() {
ch := make(chan int, 1)
ch <- 1
wg.Add(1)
go fun(ch)
wg.Wait()
}
Then output will be (try it on the Go Playground):
1
For details, see Prevent the main() function from terminating before goroutines finish in Golang

Go channel readyness

I am trying to understand channels in Go. I have read that by default sends and receives block until both the sender and receiver are ready. But how do we figure out readyness of sender and receiver.
For example in the following code
package main
import "fmt"
func main() {
ch := make(chan int)
ch <- 1
fmt.Println(<-ch)
}
The program will get stuck on the channel send operation waiting forever for someone to read the value. Even though we have a receive operation in println statement it ends up in a deadlock.
But for the following program
package main
import "fmt"
func main() {
ch := make(chan int)
go func () {
ch <- 1
}()
fmt.Println(<-ch)
}
The integer is passed successfully from go routine to main program. What made this program work? Why second works but first do not? Is go routine causing some difference?
Let's step through the first program:
// My notes here
ch := make(chan int) // make a new int channel
ch <- 1 // block until we can send to that channel
// keep blocking
// keep blocking
// still waiting for a receiver
// no reason to stop blocking yet...
// this line is never reached, because it blocks above forever.
fmt.Println(<-ch)
The second program splits the send off into its own line of execution, so now we have:
ch := make(chan int) // make a new int channel
go func () { // start a new line of execution
ch <- 1 // block this second execution thread until we can send to that channel
}()
fmt.Println(<-ch) // block the main line of execution until we can read from that channel
Since those two lines of execution can work independently, the main line can get down to fmt.Println and try and receive from the channel. The second thread will wait to send until it has.
The go routine absolutely makes a difference. The go routine that writes to the channel will be blocked until your main function is ready to read from the channel in the print statement. Having two concurrent threads, one that reads and one that writes fulfills the readiness on both sides.
In your first example, the single thread gets blocked by the channel write statement and will never reach the channel read.
You need to have a concurrent go routine to read from a channel whenever you write to it. Concurrency goes hand-in-hand with channel usage.

How to send and receive values to/from the channel within the same loop?

Here is an example:
func main() {
c := make(chan int)
i := 0
go goroutine(c)
c <- i
time.Sleep(10 * time.Second)
}
func goroutine(c chan int) {
for {
num := <- c
fmt.Println(num)
num++
time.Sleep(1 * time.Second)
c <- num
}
}
What I'm trying to do inside of goroutine is to receive number from channel, print it, increment and after one second send it back to the channel. After this I want to repeat the action.
But as a result, operation is only done once.
Output:
0
Am I doing something wrong?
By default the goroutine communication is synchronous and unbuffered: sends do not complete until there is a receiver to accept the value. There must be a receiver ready to receive data from the channel and then the sender can hand it over directly to the receiver.
So channel send/receive operations block until the other side is ready:
1. A send operation on a channel blocks until a receiver is available for the same channel: if there’s no recipient for the value on ch, no other value can be put in the channel. And the other way around: no new value can be sent in ch when the channel is not empty! So the send operation will wait until ch becomes available again.
2. A receive operation for a channel blocks until a sender is available for the same channel: if there is no value in the channel, the receiver blocks.
This is illustrated in the below example:
package main
import "fmt"
func main() {
ch1 := make(chan int)
go pump(ch1) // pump hangs
fmt.Println(<-ch1) // prints only 0
}
func pump(ch chan int) {
for i:= 0; ; i++ {
ch <- i
}
}
Because there is no receiver the goroutine hangs and print only the first number.
To workaround this we need to define a new goroutine which reads from the channel in an infinite loop.
func receive(ch chan int) {
for {
fmt.Println(<- ch)
}
}
Then in main():
func main() {
ch := make(chan int)
go pump(ch)
go receive(ch)
}
Go Playground
You create an unbuffered channel c with
c := make(chan int)
On unbuffered channels, operations are symmentrical, i.e. every send on a channel needs exactly one receive, every receive needs exactly one send. You send your i into the channel, the goroutine receives it into num. After that, the goroutine sends the incremented num into the channel, but nobody is there to receive it.
In short: The statement
c <- num
will block.
You could use a 1-buffered channel, that should work.
There is another problem with your code that you solved by waiting ten seconds in main: You don't know when your goroutine finishes. Typically, a sync.WaitGroup is used in these situations. But: Your goroutine does not finish. It's idiomatic to introduce a chan struct{} that you close in your main goroutine after a while and select over both channels in the worker goroutine.
You use unbuffered channel, so your goroutine hang on c <- num
You should use buffered channel, like this: c := make(chan int, 1)
Try it on the Go playground

Race condition with a simple channel in Go?

I'm new to Go and am stumped on what appears to be a somewhat-rare race condition with a very small block of code running on Linux with Go version 1.2.
Basically, I create a channel for an int, start a go routine to read from the channel, and then write a single int to the channel.
package main
import "fmt"
func main() {
channel := make(chan int)
go func() {
number := <- channel
fmt.Printf("GOT IT: %d\n", number)
}()
fmt.Println("[+] putting num on channel")
channel <- 42
fmt.Println("[-] putting num on channel")
}
The output about 90% of the time is as expected:
$ go run test.go
[+] putting num on channel
GOT IT: 42
[-] putting num on channel
However, about 10% of the time, the go routine simply does not read the number from the channel and prints nothing:
$ go run test.go
[+] putting num on channel
[-] putting num on channel
I'm puzzled because this code is very similar to the example at https://gobyexample.com/channels, (which I do not have this problem with) except that I'm reading from the channel in my go routine instead of writing to the channel.
Do I have a fundamental misunderstanding of how channels work or is there something else at play here?
You should wait until your goroutine executes, and then your, for example, you can do it with sync.WaitGroup:
package main
import (
"fmt"
"sync"
)
func main() {
var wg sync.WaitGroup
channel := make(chan int)
wg.Add(1)
go func() {
number := <-channel
fmt.Printf("GOT IT: %d\n", number)
wg.Done()
}()
fmt.Println("[+] putting num on channel")
channel <- 42
wg.Wait()
fmt.Println("[-] putting num on channel")
}
(goplay: http://play.golang.org/p/VycxTw_4vu)
Also you can do it with a "notification channel", that indicates that job is done:
package main
import "fmt"
func main() {
channel := make(chan int)
done := make(chan bool)
go func() {
number := <-channel
fmt.Printf("GOT IT: %d\n", number)
done <- true
}()
fmt.Println("[+] putting num on channel")
channel <- 42
<-done
fmt.Println("[-] putting num on channel")
}
(goplay: http://play.golang.org/p/fApWQgtr4D)
You seem to be expecting the receiving goroutine to run to completion before the second fmt.Println executes. This is not guaranteed to be the case. If the program terminates, goroutines are not guaranteed to reach the end of their functions.
When you see the output that doesn't display the "GOT IT" message, the channel delivered its message, but the main function completed before the goroutine did. The program terminated, and the goroutine never gets the chance to call fmt.Printf
In the example you cited, the main function ends with this:
go func() { messages <- "ping" }()
msg := <-messages
fmt.Println(msg)
Since the main function blocks until it receives a message, the goroutine always runs to completion in this example. In your code, your goroutine executes a step after it receives from the channel, and it's undefined whether the goroutine or the main function will execute the next line after the receive.
You have two goroutines, one in main() (which is implicitly a goroutine), and the anonymous one.
They communicate over a synchronous channel, so after the channel communication, it's guaranteed that they're synchronised.
At this point, the code left in the main() goroutine looks like this:
fmt.Println("[-] putting num on a channel")
and the code left in the anonymous goroutine looks like this:
fmt.Println("GOT IT: %d\n", number)
Now you're racing: the output from these Printlns may appear in either order, or even intermingled. When the Println() from main finishes, the next thing that will happen on that goroutine is that your program will be stopped. This may prevent some or all of the Println from the anonymous goroutine from appearing.

Resources