Would you tell me how work golang channel buffer? - go

Why dose not work buffer to right on the golang?
If channel become full, it is wait. This is wrong?
I don't understand how it work.
Would you tell me how work golang channel buffer?
import (
"fmt"
"runtime"
);
func main() {
runtime.GOMAXPROCS(1);
done := make(chan bool, 2);
count := 4;
go func() {
for i := 0; i < count; i++ {
done <- true
fmt.Println("AAAAAAAA", i);
}
}()
for j := 0; j < count; j++ {
<-done
fmt.Println("BBBBBBBBBB", j);
}
}
---------------------------------------------------------------------------------
AAAAAAAAAAAAAAA 0
AAAAAAAAAAAAAAA 1
AAAAAAAAAAAAAAA 2
BBBBBBBBBB 0
BBBBBBBBBB 1
BBBBBBBBBB 2
BBBBBBBBBB 3
This is my expect
AAAAAAAAAAAAAAA 0
AAAAAAAAAAAAAAA 1
BBBBBBBBBB 0
BBBBBBBBBB 1
AAAAAAAAAAAAAAA 2
AAAAAAAAAAAAAAA 3
BBBBBBBBBB 2
BBBBBBBBBB 3

The channel buffer only fills up if Go is unable to process one item before the next arrives. In your case, there's no backlog of items as each is processed quickly and efficiently.

I wanted to understand the anatomy of channels and I've made almost the same code that You've made. I've made some small changes in your code
func main() {
runtime.GOMAXPROCS(1)
done := make(chan int, 2)
count := 4
go func() {
defer close(done)
for i := 0; i < count; i++ {
done <- i
fmt.Println("AAAAAAAA", i)
}
}()
for j := 0; j < count; j++ {
i, ok := <-done
if !ok {
break
}
fmt.Println("BBBBBBBBBB", i)
}
time.Sleep(1 * time.Millisecond)
}
Now, the output will be this
AAAAAAAA 0
AAAAAAAA 1
AAAAAAAA 2
BBBBBBBBBB 0
BBBBBBBBBB 1
BBBBBBBBBB 2
BBBBBBBBBB 3
AAAAAAAA 3
I have found an interesting information about this in the book of Concurrency in Go - by Cox-Buday, Katherine
It also bears mentioning that if a buffered channel is empty and has a
receiver, the buffer will be bypassed and the value will be passed
directly from the sender to the receiver.
According this information my understanding is, when we have a buffered channel with capacity 2:
-> main goroutine is blocked, because the channel is empty
AAAAAAAA 0 -> because, there is an active receiver this value bypassed the channel
AAAAAAAA 1 -> this value is the first value in the channel
AAAAAAAA 2 -> this value is the second value in the channel and channel is full now, so this goroutine is blocked
BBBBBBBBBB 0 -> the main goroutine can unblock now and read the "bypassed" value
-> i think the anonymous goroutine can pass the third value to channel somewhere i here
BBBBBBBBBB 1 -> the main goroutine reads the first value from the channel
BBBBBBBBBB 2 -> the main goroutine reads the second value from the channel
BBBBBBBBBB 3 -> the main goroutine reads the third value
-> the main goroutine blocked by sleep
AAAAAAAA 3 -> the anonymous goroutine can run the print statement
I'm not 100% sure this happening, but It is my observation. Unbuffered channel is also buffered channel but with 0(or 1) capacity. It is also interesting, if you try your code with 0 (unbuffered) capacity. The result will be something like this:
AAAAAAAA 0
BBBBBBBBBB 0
BBBBBBBBBB 1
AAAAAAAA 1
AAAAAAAA 2
BBBBBBBBBB 2
BBBBBBBBBB 3
AAAAAAAA 3
Finally, here is my code. I used buffer for storing the results and write it out to stdout only at the end of the main function.
func main() {
runtime.GOMAXPROCS(1)
var stdoutBuff bytes.Buffer
defer stdoutBuff.WriteTo(os.Stdout)
intStream := make(chan int, 0)
go func() {
defer close(intStream)
defer fmt.Fprintln(&stdoutBuff, "Producer done.")
for i := 0; i < 5; i++ {
fmt.Fprintf(&stdoutBuff, "Before Sending: %d\n", i)
intStream <- i
fmt.Fprintf(&stdoutBuff, "After Sending: %d\n", i)
}
}()
// for integer := range intStream {
// fmt.Fprintf(&stdoutBuff, "Received: %v\n", integer)
// }
for {
fmt.Fprintf(&stdoutBuff, "Before received.\n")
v, ok := <-intStream
if !ok {
break
}
fmt.Fprintf(&stdoutBuff, "Received: %v\n", v)
}
}
I hope it helps a little bit.

Related

At which point a routine actually blocks?

I define unbuffered channel and do these
1.Write some values into it in one go routine.
2.Read values from it in main go routine.
Following the example
package main
import "fmt"
func main() {
c := make(chan int)
go func() {
for i := 0;i < 3; i++ {
c <- i
fmt.Printf("write %v to channel\n", i)
}
}()
for i := 0; i < 3; i++ {
res := <-c
fmt.Printf("read %v from channel\n", res)
}
}
Output
write 0 to channel
read 0 from channel
read 1 from channel
write 1 to channel
write 2 to channel
read 2 from channel
I do not understand the ordering.
After "read 0 from channel", how does it prints "read 1 from channel" after that event it has not been pushed in channel ?
I read the statements like once value is pushed into it and go routine gets blocked until some other go routine reads value from it. But at what point (or which line in above example) it gets blocked ?
Can someone explain ?
The problem is with fmt.Printf, there is no guarantee your output will not be mixed.

issue with go routine and channel

I am learning go routines and channels,here is a basic program which i tried on the topic ,I am getting error that fatal error: all goroutines are asleep - deadlock! and I also want to know why length of my channel is zero.
package main
import (
"fmt"
)
func main() {
mychannel := make(chan int)
go takeChn(mychannel)
fmt.Println("length", len(mychannel))
for res := range mychannel {
fmt.Println("firstFunc", res, len(mychannel))
}
}
func takeChn(c chan int) {
for i := 0; i < 10; i++ {
c <- (i + 1)
}
}
The length of the channel is zero, because it is an unbuffered channel. It does not store any elements.
Your program deadlocks because the for-loop never terminates. The range over the channel will terminate when the channel is closed, but you never close the channel.
If you close the channel at the end of the goroutine, the program will run without a deadlock.
Modifying the code as per Burak Serdar's input by closing the channel
package main
import (
"fmt"
)
func main() {
mychannel := make(chan int)
go takeChn(mychannel)
fmt.Println("length", len(mychannel))
for res := range mychannel {
fmt.Println("firstFunc", res, len(mychannel))
}
}
func takeChn(c chan int) {
for i := 0; i < 10; i++ {
c <- (i + 1)
}
close(c)
}
Output:
length 0
firstFunc 1 0
firstFunc 2 0
firstFunc 3 0
firstFunc 4 0
firstFunc 5 0
firstFunc 6 0
firstFunc 7 0
firstFunc 8 0
firstFunc 9 0
firstFunc 10 0

Is it necessary to close a channel when sending data is finished?

Here is my program.
package main
import "fmt"
func init() {
fmt.Println("init function")
}
func main() {
// gen number to naturals channel
naturals := gen(1, 2, 3)
// write the squars in a channel
squar := dosquar(naturals)
for p := range squar {
fmt.Println("printer shows----- ", p)
}
}
func gen(nums ...int) chan int {
naturals := make(chan int)
go func() {
for _, n := range nums {
fmt.Println("generating number ", n)
naturals <- n
fmt.Println("generated number ", n)
}
//close(naturals)
}()
return naturals
}
func dosquar(naturals chan int) chan int {
// write the squars the values
squar := make(chan int)
go func() {
for number := range naturals {
fmt.Println("recieved number ", number)
squar <- number * number
fmt.Println("sent squar of number ", number*number)
}
//close(squar)
}()
return squar
}
It gives following error.
init function
generating number 1
generated number 1
generating number 2
recieved number 1
sent squar of number 1
recieved number 2
generated number 2
generating number 3
printer shows----- 1
printer shows----- 4
sent squar of number 4
recieved number 3
sent squar of number 9
printer shows----- 9
generated number 3
fatal error: all goroutines are asleep - deadlock!
goroutine 1 [chan receive]:
main.main()
/Users/siyaram/go/src/github.com/SrmHitter9062/go-pipeline/main.go:15 +0x127
goroutine 19 [chan receive]:
I expect it to be running as channels are being ranged.That leads me to a question that do we need to close the channel every time, when we are finished with them ?
Please somebody help clarifying why program is not working as expected.
You can do whatever you want, but a range loop over a channel won't exit until the channel is closed.

Understanding a Deadlock in Go

I have the following excerpt from an example given in a programming course, and I am not sure why a deadlock is occurring.
package main
import (
"fmt"
)
var (
Count int = 0
nFunctions int = 2
)
var sema = make(chan int)
func increment(ch chan int, nSteps int) {
for i := 0; i < nSteps; i++ {
<- sema
cnt := Count
Count = cnt + 1
ch <- 1
sema <- 1
}
return
}
func main() {
ch := make(chan int)
sema <- 1
go increment(ch, 1000)
go increment(ch, 1000)
for i := 0; i < nFunctions*1000; i++ {
<-ch
}
fmt.Printf("Count = %d\n", Count)
}
Strangely, the deadlock does not occur when I change the statement, in the main, from sema <- 1 to
go func () {
sema <- 1
}()
Any explanations for this much appreciated. The error message is :
fatal error: all goroutines are asleep - deadlock!
goroutine 1 [chan send]:
main.main()
Channels block both the sender and the receiver. If you send something, you are blocked until it is received. You could reduce your code even further, all you need is a channel and then write to that channel. Note that you could also use a buffered channel, which allows writes up to the buffer length without blocking. If the buffer is full however, it does still block.

Channel buffer taking one more value than expected in Go

I thought that channels in Go only hold 1 value by default unless the buffer size if specified. I read that here. But when I run this:
func main (){
for i := range numGen(6) {
log.Println("taking from channel", i)
}
}
func numGen(num int) chan int {
c := make(chan string)
go func() {
for i := 0; i < num; i++ {
log.Println("passing to channel", i)
c <- i
}
close(c)
}
return c
}
my output is:
2017/06/13 18:09:08 passing to channel 0
2017/06/13 18:09:08 passing to channel 1
2017/06/13 18:09:08 taking from channel 0
2017/06/13 18:09:08 taking from channel 1
2017/06/13 18:09:08 passing to channel 2
2017/06/13 18:09:08 passing to channel 3
2017/06/13 18:09:08 taking from channel 2
2017/06/13 18:09:08 taking from channel 3
2017/06/13 18:09:08 passing to channel 4
2017/06/13 18:09:08 passing to channel 5
2017/06/13 18:09:08 taking from channel 4
2017/06/13 18:09:08 taking from channel 5
which shows that the channel is holding 2 values at a time. Specifying a buffer size like this
c := make(chan int, 0)
does nothing. Any way I could make it only hold 1, value, not 2?
which shows that the channel is holding 2 values at a time.
Thats not the case. This is how the code executes:
The main goroutine blocks on a read on the channel
The second goroutine writes to the channel and continues executing.
The second goroutine blocks at the second write attempt because noone is reading
The main goroutine continues executing, prints the read number
The main goroutine reads another number since someone is writing to it
The main goroutine prints the read number and blocks on the next read
The second goroutine continues executing at step 2.
There is no buffer, just concurrency.
package main
import (
"log"
)
func main() {
seq := make(chan bool)
for i := range numGen(6, seq) {
<-seq
log.Println("taking from channel", i)
}
}
func numGen(num int, seq chan bool) chan int {
c := make(chan int)
go func() {
for i := 0; i < num; i++ {
c <- i
log.Println("passing to channel", i)
seq <- true // 要保证顺序,这里发送一个信号量。
}
close(c)
}()
return c
}

Resources