I am studying ‘Go Concurrency Pattern' from https://talks.golang.org/2012/concurrency.slide#25'
Question:
How the channel share variable from it's outside ? In this case i has been shared.
Variable at point A and point B seems to have some special relation ? What is it ?
What does it means for ?
for i := 0; ; i++
Main code:
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++ { // <--------- point B
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 main() {
c := boring("boring!") // Function returning a channel.
for i := 0; i < 5; i++ { // <--------- point A
fmt.Printf("You say: %q\n", <-c)
}
fmt.Println("You're boring; I'm leaving.")
}
output:
You say: "boring! 0"
You say: "boring! 1"
You say: "boring! 2"
You say: "boring! 3"
You say: "boring! 4"
You're boring; I'm leaving.
Program exited.
The for (i := 0; ; i++) { } creates an index the increments forever.
When you make(chan string ) you've created a read/write channel. You also reference the channel inside the go function and pass it out as the return value. Go does an analysis of how variables are used called "escape analysis" and chooses whether to make the channel on the heap or on the stack, in your case on the heap so that when the function creating the channel exits the channel doesn't get deallocated.
Related
I am trying hard to understand concurrency in Go.
package main
import "fmt"
func sendValues(myIntChannel chan int) {
for i := 0; i < 5; i++ {
myIntChannel <- i //sending value
}
}
func main() {
myIntChannel := make(chan int)
defer close(myIntChannel)
go sendValues(myIntChannel)
for value := range myIntChannel {
fmt.Println(value) //receiving value
}
}
Above code is giving below output:
0
1
2
3
4
fatal error: all goroutines are asleep - deadlock!
goroutine 1 [chan receive]:
main.main()
/Users/spikki/Desktop/GoLearning/go_channel.go:51 +0x10b
As per my understanding, defer function will execute after completion of its surrounding functions. I am not able to interpret it.
If I use for loop to receive the values from the channel its working as below.
for i := 0; i < 5; i++ {
fmt.Println(<-myIntChannel) //receiving value
}
Can anyone help me to understand this concept?
for ... range over a channel terminates only once all values have been received from the channel and the channel has been closed.
In your example you wish to close the channel in a deferred function, but that would only run when main() returns. But main() would only return if the loop would end. This is the cause of deadlock. The for loop waits for the channel to be closed, and closing the channel waits for the for loop to end.
When you use a loop to receive exactly 5 values form the channel, it works because the launched goroutines sends 5 values on it. This loop doesn't wait for the channel to be closed, so the loop can end, and so can the main() function.
That's why the sender should close the channel (not the receiver), and problem is solved immediately:
func sendValues(myIntChannel chan int) {
for i := 0; i < 5; i++ {
myIntChannel <- i //sending value
}
close(myIntChannel)
}
func main() {
myIntChannel := make(chan int)
go sendValues(myIntChannel)
for value := range myIntChannel {
fmt.Println(value) //receiving value
}
}
Output (try it on the Go Playground):
0
1
2
3
4
To explain it in a bit different terms, what your code does is:
func main() {
...
while myIntChannel is not closed {
...
}
close myIntChannel
}
Now you can see where the deadlock comes from.
While the above answer is valid, you could also try this, if you prefer using defer:
func sendValues(myIntChannel chan int) {
defer close(myIntChannel)
for i := 0; i < 5; i++ {
myIntChannel <- i //sending value
}
}
func main() {
myIntChannel := make(chan int)
go sendValues(myIntChannel)
for value := range myIntChannel {
fmt.Println(value) //receiving value
}
}
I want to replace the channel with a new one under some condition, for example:
package main
import (
"log"
"time"
)
func subMsg(s string) chan string {
ch := make(chan string)
go func() {
ticker := time.NewTicker(time.Second * 2)
for range ticker.C {
ch <- s
}
}()
return ch
}
func main() {
chStr := subMsg("hello")
go func() {
i := 0
for s := range chStr {
log.Print(s)
i++
if i > 5 {
log.Print("new topic")
i = 0
chStr = subMsg("world")
}
}
}()
select {}
}
I expect this code snippet outputs 5 "hello", then "world", but it didn't work this way. I am not very clear about what happened when I re-assign a channel. Any suggestions?
You are using for range, and per Spec: For statements the range expression is only evaluated once.
The range expression x is evaluated once before beginning the loop, with one exception: if at most one iteration variable is present and len(x) is constant, the range expression is not evaluated.
The chStr variable is not checked by the for loop later on, so changing its value has no effect.
You can't use for range if you want to switch over to another channel.
Simply use a "normal" loop and receive from the channel inside it. Use the special form x, ok := <-ch so you know when the channel is closed, and so you can break from the loop (to mimic the for range working):
for {
s, ok := <-chStr
if !ok {
break
}
log.Print(s)
i++
if i > 5 {
log.Print("new topic")
i = 0
chStr = subMsg("world")
}
}
Try it on the Go Playground.
The following program never prints "Full". With fmt.Println(len(choke)) uncommented, the program outputs "Full" when the channel is full.
package main
import (
"fmt"
)
func main() {
choke := make(chan string, 150000)
go func() {
for i := 0; i < 10000000; i++ {
choke <- string(i)
fmt.Println("i=", i)
}
}()
for {
//fmt.Println(len(choke))
if len(choke) >= 150000 {
fmt.Println("Full")
}
}
}
#tim-heckman explained the cause of this behavior in OP.
How do I detect a channel is full without using a hot loop?
Use a select statement on the write side. It will write to the channel if there is buffer available or a receiver waiting; it will fallthrough to the default case if the channel is full.
func main() {
choke := make(chan string, 150000)
var i int
for {
select {
case choke <- string(i):
i++
default:
fmt.Println("Full")
return
}
}
}
I try use "sync.mutex" protect my func,but i found that the lock still uses the caller to destroy it.
var mutex sync.mutex
This is error:
//caller use
func a() {
for i := 0; i < 10; i++ {
go b(i)
}
}
//My func
func b(i int) {
mutex.Lock()
fmt.Println(i)
mutex.Unlock()
}
this is success,but destroyed my encapsulation method:
//caller use
func a() {
for i := 0; i < 10; i++ {
mutex.Lock()
go b(i)
}
}
//my func
func b(i int) {
fmt.Println(i)
mutex.Unlock()
}
Thanks
The Go Programming Language Specification
Exported identifiers
An identifier may be exported to permit access to it from another
package. An identifier is exported if both:
the first character of the identifier's name is a Unicode upper case letter (Unicode class "Lu"); and
the identifier is declared in the package block or it is a field name or method name.
All other identifiers are not exported.
Put the function in its own package and don't export the mutex. For example.
package b
import (
"fmt"
"sync"
)
var mutex sync.Mutex
func B(i int) {
mutex.Lock()
fmt.Println(i)
mutex.Unlock()
}
To use,
package a
import "b"
func a() {
for i := 0; i < 10; i++ {
go b.B(i)
}
}
In the first example, all the calls to go b(i) are called in a's loop, but the loop can be finished before any of the goroutines have a chance to start, so if main returns, then all those goroutines stop.
In the second example, the mutex locks and doesn't unlock until Unlock is called in each of the b goroutines. The result is that the calls are completely sequential since each iteration of the loop in a can't start until the last iteration's b goroutine finishes and calls Unlock.
A better practice in Go would be for your b function to take in a pointer to the mutex along with the number passed in, so in your original example it would look like:
//caller use
func a() {
var wg sync.WaitGroup
for i := 0; i < 10; i++ {
wg.Add(1)
go func() {
defer wg.Done()
b(&mutex, i)
}()
}
wg.Wait()
}
//My func
func b(mutex *sync.Mutex, i int) {
mutex.Lock()
fmt.Println(i)
mutex.Unlock()
}
Which would remove reliance on a global variable and also guarantee that all calls to b are using the exact same mutex since we pass in a pointer to one mutex
This question already has answers here:
What is channel buffer size?
(3 answers)
Closed 7 years ago.
I went through a series of definitions to figure out how the buffer works but I just don't get it. Here is an example below, I changed the value of the buffer but I have no clue about what it does. Can some one explain it to me based on this example and provide some test cases of how/why it's working? Thanks.
package main
import (
"fmt"
"time"
)
func send(out, finish chan bool) {
for i := 0; i < 5; i++ {
out <- true
time.Sleep(1 * time.Second)
fmt.Println("Fin d'une écriture")
}
finish <- true
close(out)
}
func recv(in, finish chan bool) {
for _ = range in {
fmt.Println("Fin d'une lecture")
time.Sleep(10 * time.Second)
}
finish <- true
}
func main() {
chanFoo := make(chan bool, 3)
chanfinish := make(chan bool)
go send(chanFoo, chanfinish)
go recv(chanFoo, chanfinish)
<-chanfinish
<-chanfinish
}
If a channel does not have a buffer then only a single item can be sent on it at a time. This means code that sends on it will block until some receiver reads the item out of the channel. Here's a contrived example; https://play.golang.org/p/HM8jdIFqsN
package main
import (
"fmt"
)
func main() {
blocker := make(chan bool)
nonBlocker := make(chan bool, 5)
for i := 0; i < 5; i++ {
nonBlocker <- true
fmt.Println("We keep going")
}
go func () {
for i := 0; i < 5; i++ {
blocker <- true
fmt.Println("We block cause that channel is full")
} }()
}
There's plenty of other things I could do to demonstrate the same but the basic idea is, if you pass a channel into some goroutine and the channel is not buffered, the goroutine which sends on the channel will block until the item it sent is received. With a buffered channel you can send as long as the buffer isn't at capacity. Basically, if you spin up goroutines which are doing work and returning the results and they're moving faster than the code that spawned them, you may want to use a buffered channel to open up that bottle neck.
EDIT: If it's still not obvious what's happening look at this; https://play.golang.org/p/9SXc4M1to4
package main
import (
"fmt"
)
func main() {
blocker := make(chan bool)
nonBlocker := make(chan bool, 5)
for i := 0; i < 5; i++ {
nonBlocker <- true
fmt.Println("We keep going")
}
go func () {
for i := 0; i < 5; i++ {
blocker <- true
fmt.Println("Now we see this cause the reciever keeps opening the channel up again!")
} }()
for i := 0; i < 5; i++ {
<-blocker
}
}