what's wrong with the golang code by using ticker - go

package main
import (
"fmt"
"time"
)
func main() {
intChan := make(chan int, 1)
ticker := time.NewTicker(time.Second)
go func() {
for _ = range ticker.C {
select {
case intChan <- 1:
case intChan <- 2:
case intChan <- 3:
}
}
/*defer */
fmt.Println("End. [sender]")
}()
var sum int
for e := range intChan {
fmt.Printf("Received: %v\n", e)
sum += e
if sum > 10 {
fmt.Printf("Got: %v\n", sum)
break
//ticker.Stop()
}
}
fmt.Println("End. [receiver]")
//time.Sleep(10)
}
I'm new in golang. In this code, I want print "End. [sender]" once when the goroutine is over.
I try to use ticker.stop(), or even time.sleep(), defer , but no effect.
What's wrong with it, please give me some idea. thanks

As documentation says, ticker.Stop doesn't close channel. So you must not expect break-loop. You can add new channel for quit.
package main
import (
"fmt"
"time"
)
func main() {
intChan := make(chan int, 2)
ticker := time.NewTicker(time.Second)
quit := make(chan bool)
go func() {
loop:
for {
select {
case <-ticker.C:
select {
case intChan <- 1:
case intChan <- 2:
case intChan <- 3:
}
case <-quit:
break loop
}
}
/*defer */
fmt.Println("End. [sender]")
close(intChan)
}()
var sum int
for e := range intChan {
fmt.Printf("Received: %v\n", e)
sum += e
if sum > 10 {
fmt.Printf("Got: %v\n", sum)
quit <- true
//break
//ticker.Stop()
}
}
fmt.Println("End. [receiver]")
//time.Sleep(10)
}

Related

self-training task

I need limit running function by maxTasks variable. Can you check my answer and possible to make adjustments.
package main
import (
"fmt"
"math/rand"
"time"
)
func main() {
maxTasks := 10
var tasks []func()
for x := 0; x < 50; x++ {
fmt.Println("add new task with num ", x)
tasks = append(tasks, func(x int) func() {
fmt.Println("create function with ", x)
return func() {
worktime := rand.Intn(10)
time.Sleep(time.Duration(worktime) * time.Second)
fmt.Println("current task:",x )
fmt.Println(" with worktime ",worktime)
}
}(x))
}
//tasks[0]()
ch := make(chan int, maxTasks)
for _, task := range tasks {
go func(t func()) {
ch <- 1
t()
fmt.Println("current task:",len(ch))
<- ch
}(task)
}
time.Sleep(10000 * time.Second)
}

go routine for range over channels

I have been working in Golang for a long time. But still I am facing this problem though I know the solution to my problem. But never figured out why is it happening.
For example If I have a pipeline situation for inbound and outbound channels like below:
package main
import (
"fmt"
)
func main() {
for n := range sq(sq(gen(3, 4))) {
fmt.Println(n)
}
fmt.Println("Process completed")
}
func gen(nums ...int) <-chan int {
out := make(chan int)
go func() {
for _, n := range nums {
out <- n
}
close(out)
}()
return out
}
func sq(in <-chan int) <-chan int {
out := make(chan int)
go func() {
for n := range in {
out <- n * n
}
close(out)
}()
return out
}
It does not give me a deadlock situation. But if I remove the go routine inside the outbound code as below:
func sq(in <-chan int) <-chan int {
out := make(chan int)
for n := range in {
out <- n * n
}
close(out)
return out
}
I received a deadlock error. Why is it so that looping over channels using range without go routine gives a deadlock.
This situation caused of output channel of sq function is not buffered. So sq is waiting until next function will read from output, but if sq is not async, it will not happen (Playground link):
package main
import (
"fmt"
"sync"
)
var wg sync.WaitGroup
func main() {
numsCh := gen(3, 4)
sqCh := sq(numsCh) // if there is no sq in body - we are locked here until input channel will be closed
result := sq(sqCh) // but if output channel is not buffered, so `sq` is locked, until next function will read from output channel
for n := range result {
fmt.Println(n)
}
fmt.Println("Process completed")
}
func gen(nums ...int) <-chan int {
out := make(chan int)
go func() {
for _, n := range nums {
out <- n
}
close(out)
}()
return out
}
func sq(in <-chan int) <-chan int {
out := make(chan int, 100)
for n := range in {
out <- n * n
}
close(out)
return out
}
Your function creates a channel, writes to it, then returns it. The writing will block until somebody can read the corresponding value, but that's impossible because nobody outside this function has the channel yet.
func sq(in <-chan int) <-chan int {
// Nobody else has this channel yet...
out := make(chan int)
for n := range in {
// ...but this line will block until somebody reads the value...
out <- n * n
}
close(out)
// ...and nobody else can possibly read it until after this return.
return out
}
If you wrap the loop in a goroutine then both the loop and the sq function are allowed to continue; even if the loop blocks, the return out statement can still go and eventually you'll be able to connect up a reader to the channel.
(There's nothing intrinsically bad about looping over channels outside of goroutines; your main function does it harmlessly and correctly.)
The reason of the deadlock is because the main is waiting for the sq return and finish, but the sq is waiting for someone read the chan then it can continue.
I simplified your code by removing layer of sq call, and split one sentence into 2 :
func main() {
result := sq(gen(3, 4)) // <-- block here, because sq doesn't return
for n := range result {
fmt.Println(n)
}
fmt.Println("Process completed")
}
func gen(nums ...int) <-chan int {
out := make(chan int)
go func() {
for _, n := range nums {
out <- n
}
close(out)
}()
return out
}
func sq(in <-chan int) <-chan int {
out := make(chan int)
for n := range in {
out <- n * n // <-- block here, because no one is reading from the chan
}
close(out)
return out
}
In sq method, if you put code in goroutine, then the sq will returned, and main func will not block, and consume the result queue, and the goroutine will continue, then there is no block any more.
func main() {
result := sq(gen(3, 4)) // will not blcok here, because the sq just start a goroutine and return
for n := range result {
fmt.Println(n)
}
fmt.Println("Process completed")
}
func gen(nums ...int) <-chan int {
out := make(chan int)
go func() {
for _, n := range nums {
out <- n
}
close(out)
}()
return out
}
func sq(in <-chan int) <-chan int {
out := make(chan int)
go func() {
for n := range in {
out <- n * n // will not block here, because main will continue and read the out chan
}
close(out)
}()
return out
}
The code is a bit complicated,
Let's simplify
First eq below, not has deadLock
func main() {
send := make(chan int)
receive := make(chan int)
go func() {
send<-3
send<-4
close(send)
}()
go func() {
receive<- <-send
receive<- <-send
close(receive)
}()
for v := range receive{
fmt.Println(v)
}
}
Second eq below,remove "go" has deadLock
func main() {
send := make(chan int)
receive := make(chan int)
go func() {
send<-3
send<-4
close(send)
}()
receive<- <-send
receive<- <-send
close(receive)
for v := range receive{
fmt.Println(v)
}
}
Let's simplify second code again
func main() {
ch := make(chan int)
ch <- 3
ch <- 4
close(ch)
for v := range ch{
fmt.Println(v)
}
}
The reason of the deadlock is no buffer channel waiting in main goroutine.
Two Solutions
// add more cap then "channel<-" time
func main() {
ch := make(chan int,2)
ch <- 3
ch <- 4
close(ch)
for v := range ch{
fmt.Println(v)
}
}
//async "<-channel"
func main() {
ch := make(chan int)
go func() {
for v := range ch {
fmt.Println(v)
}
}()
ch <- 3
ch <- 4
close(ch)
}
My understanding is
when the main thread is blocked for waiting for the chan to be writen or read, Go will detect if any other Go routine is running. If there is no any other Go routine running, it will have "fatal error: all goroutines are asleep - deadlock!"
I tested if by using the below simple case
func main() {
c := make(chan int)
go func() {
time.Sleep(10 * time.Second)
}()
c <- 1
}
The deadlock error is reported after 10 seconds.

Golang Channels dealing with send != receive

Consider the toy example below. The code works perfectly but when you interchange the 2 lines marked as replace, there will be a deadlock. Is there a better way to deal with such a situation when you have different number of sends and receives?
package main
import "fmt"
import "strconv"
func main() {
a := make(chan string)
b := make(chan string)
go func() {
for i := 0; i < 2; i++ {
go func(i int) {
fmt.Println(<-a)
b <- strconv.Itoa(i) + "b" // replace
a <- strconv.Itoa(i) + "a" // replace
}(i)
}
}()
a <- "0"
for i := 0; i < 2; i++ {
fmt.Println(<-b)
}
}
EDIT: using a select statement, there's a chance that a gets picked up by the select and there's still no way to prevent a deadlock because the goroutines can't execute
package main
import "fmt"
import "strconv"
func main() {
a := make(chan string)
b := make(chan string)
c := make(chan bool)
cancel := make(chan bool)
go func() {
for i := 0; i < 2; i++ {
go func(i int) {
fmt.Println(<-a)
b <- strconv.Itoa(i) + "b" // replace
a <- strconv.Itoa(i) + "a" // replace
c <- true
}(i)
}
}()
go func() {
<-c
<-c
cancel <- true
}()
a <- "0"
loop:
for {
select {
case ain := <-a:
fmt.Println("select", ain)
case bin := <-b:
fmt.Println("select", bin)
case <-cancel:
break loop
}
}
}
Use select:
package main
import "fmt"
import "strconv"
func main() {
a := make(chan string)
b := make(chan string)
go func() {
for i := 0; i < 2; i++ {
go func(i int) {
fmt.Println(<-a)
b <- strconv.Itoa(i) + "b" // replace
a <- strconv.Itoa(i) + "a" // replace
}(i)
}
}()
// regardless of which comes in first, this will handle it
select {
case ain <- a:
fmt.Println("sent a", ain)
case bin <- b:
fmt.Println("sent b", bin)
case <- cancel:
break
}
}
That example will sit and block for an item sent on either a or b channels.
Optionally I usually set a cancel token or a timeout.
Your original code deadlocks on the switch because you sent on B, where you were only listening on A. Golang requires you to be listening on the channel BEFORE you ever send to it. This is the pattern for multiple channels, not knowing which you are going to get first.

Golang channels using select doesn't stop

Go-lang newbie here. I am trying out Go's Tour of Go, and came across an exercise about channels (https://tour.golang.org/concurrency/7).
The idea is to walk two trees and then evaluate if the trees are equivalent.
I wanted to solve this exercise using a select waiting for results from both channels. When both would finish I evaluate the resulting slice. Unfortunately the method goes on an infinite loop. I added some output to see what was happening and noticed that only one of the channels was being closed, and then opened again.
I am clearly doing something wrong, but I can't see what.
My question is what am I doing wrong? What assumption am I making regarding the closing of channels that makes the code below go into an infinite loop?
package main
import (
"golang.org/x/tour/tree"
"fmt"
)
// Walk walks the tree t sending all values
// from the tree to the channel ch.
func Walk(t *tree.Tree, ch chan int) {
_walk(t, ch)
close(ch)
}
func _walk(t *tree.Tree, ch chan int) {
if (t.Left != nil) {
_walk(t.Left, ch)
}
ch <- t.Value
if (t.Right != nil) {
_walk(t.Right, ch)
}
}
// Same determines whether the trees
// t1 and t2 contain the same values.
func Same(t1, t2 *tree.Tree) bool {
ch1 := make(chan int)
ch2 := make(chan int)
go Walk(t1, ch1)
go Walk(t2, ch2)
var out1 []int
var out2 []int
var tree1open, tree2open bool
var tree1val, tree2val int
for {
select {
case tree1val, tree1open = <- ch1:
out1 = append(out1, tree1val)
case tree2val, tree2open = <- ch2:
out2 = append(out2, tree2val)
default:
if (!tree1open && !tree2open) {
break
} else {
fmt.Println("Channel open?", tree1open, tree2open)
}
}
}
if (len(out1) != len(out2)) {
return false
}
for i := 0 ; i < len(out1) ; i++ {
if (out1[i] != out2[i]) {
return false
}
}
return true
}
func main() {
ch := make(chan int)
go Walk(tree.New(1), ch)
for i := range ch {
fmt.Println(i)
}
fmt.Println(Same(tree.New(1), tree.New(1)))
fmt.Println(Same(tree.New(1), tree.New(2)))
}
A "break" statement terminates execution of the innermost "for", "switch" or "select" statement.
see: http://golang.org/ref/spec#Break_statements
the break statement in your example terminates the select statement, the "innermost" statement.
so add label: ForLoop before for loop and add break ForLoop
ForLoop:
for {
select {
case tree1val, tree1open = <-ch1:
if tree1open {
out1 = append(out1, tree1val)
} else if !tree2open {
break ForLoop
}
case tree2val, tree2open = <-ch2:
if tree2open {
out2 = append(out2, tree2val)
} else if !tree1open {
break ForLoop
}
}
}
don't read the rest if you want to solve that problem yourself, and come back when you are done:
solution 1 (similar to yours):
package main
import "fmt"
import "golang.org/x/tour/tree"
// Walk walks the tree t sending all values
// from the tree to the channel ch.
func Walk(t *tree.Tree, ch chan int) {
_walk(t, ch)
close(ch)
}
func _walk(t *tree.Tree, ch chan int) {
if t.Left != nil {
_walk(t.Left, ch)
}
ch <- t.Value
if t.Right != nil {
_walk(t.Right, ch)
}
}
// Same determines whether the trees
// t1 and t2 contain the same values.
func Same(t1, t2 *tree.Tree) bool {
ch1, ch2 := make(chan int), make(chan int)
go Walk(t1, ch1)
go Walk(t2, ch2)
tree1open, tree2open := false, false
tree1val, tree2val := 0, 0
out1, out2 := make([]int, 0, 10), make([]int, 0, 10)
ForLoop:
for {
select {
case tree1val, tree1open = <-ch1:
if tree1open {
out1 = append(out1, tree1val)
} else if !tree2open {
break ForLoop
}
case tree2val, tree2open = <-ch2:
if tree2open {
out2 = append(out2, tree2val)
} else if !tree1open {
break ForLoop
}
}
}
if len(out1) != len(out2) {
return false
}
for i, v := range out1 {
if v != out2[i] {
return false
}
}
return true
}
func main() {
ch := make(chan int)
go Walk(tree.New(1), ch)
for i := range ch {
fmt.Println(i)
}
fmt.Println(Same(tree.New(1), tree.New(1)))
fmt.Println(Same(tree.New(1), tree.New(2)))
}
output:
1
2
3
4
5
6
7
8
9
10
true
false
another way:
package main
import "fmt"
import "golang.org/x/tour/tree"
// Walk walks the tree t sending all values
// from the tree to the channel ch.
func Walk(t *tree.Tree, ch chan int) {
_walk(t, ch)
close(ch)
}
func _walk(t *tree.Tree, ch chan int) {
if t != nil {
_walk(t.Left, ch)
ch <- t.Value
_walk(t.Right, ch)
}
}
// Same determines whether the trees
// t1 and t2 contain the same values.
func Same(t1, t2 *tree.Tree) bool {
ch1, ch2 := make(chan int), make(chan int)
go Walk(t1, ch1)
go Walk(t2, ch2)
for v := range ch1 {
if v != <-ch2 {
return false
}
}
return true
}
func main() {
ch := make(chan int)
go Walk(tree.New(1), ch)
for v := range ch {
fmt.Println(v)
}
fmt.Println(Same(tree.New(1), tree.New(1)))
fmt.Println(Same(tree.New(1), tree.New(2)))
}
output:
1
2
3
4
5
6
7
8
9
10
true
false
and see:
Go Tour Exercise: Equivalent Binary Trees
The suggestion by Amd is a valid one in the previous answer. However, looking at the problem you're trying to solve, it still does not solve the it. (If you run the program, it will output true for both the cases)
Here's the problem:
for {
select {
case tree1val, tree1open = <-ch1:
out1 = append(out1, tree1val)
case tree2val, tree2open = <-ch2:
out2 = append(out2, tree2val)
default:
//runtime.Gosched()
if !tree1open && !tree2open {
break ForLoop
} else {
fmt.Println("Channel open?", tree1open, tree2open)
}
}
}
In this case, since the default values of tree1open and tree2open are false (according to golang specification), it goes to the 'default' case, because select is non-blocking, and simply breaks from the ForLoop, without even filling the out1 and out2 slices (possibly, since these are goroutines). Hence the lengths of out1 and out2 remain zero, due to which it outputs true in most cases.
Here is the correction:
ForLoop:
for {
select {
case tree1val, tree1open = <-ch1:
if tree1open {
out1 = append(out1, tree1val)
}
if !tree1open && !tree2open {
break ForLoop
}
case tree2val, tree2open = <-ch2:
if tree2open {
out2 = append(out2, tree2val)
}
if !tree1open && !tree2open {
break ForLoop
}
default:
}
}
The key thing to note is that we have to check whether the channels have been closed in both cases (equivalent to saying whether tree1open and tree2open are both false). Here, it will correctly fill up out1 and out2 slices and then further compare their respective values.
The check for tree1open (or tree2open) being true has been added before append simply to avoid appending zero values to out1 (or out2).
Thanks,

Goroutine sleep and deadlock in code. How to solve it?

http://play.golang.org/p/r92-KtQEGl
I am trying to execute this code. It throws a deadlock error.
What am I missing?
package main
import "tour/tree"
import "fmt"
// Walk walks the tree t sending all values
// from the tree to the channel ch.
func Walk(t *tree.Tree, ch chan int){
var temp chan int
ch <- t.Value
if t.Left!=nil{go Walk(t.Left,temp)}
if t.Right!=nil{go Walk(t.Right,temp)}
for i := range temp{
ch <- i
}
close(ch)
}
// Same determines whether the trees
// t1 and t2 contain the same values.
func Same(t1, t2 *tree.Tree) bool
You need at least to initialize your channels (if the channel is nil, a range would block forever)
var temp chan int = make(chan int)
var ch chan int = make(chan int)
See http://play.golang.org/p/Gh8MZlyd3B (still deadlock but at least display results)
This version, using two temp channels, doesn't deadlock: http://play.golang.org/p/KsnmKTgZ83
package main
import "tour/tree"
import "fmt"
// Walk walks the tree t sending all values
// from the tree to the channel ch.
func Walk(t *tree.Tree, ch chan int) {
var temp1 chan int = make(chan int)
var temp2 chan int = make(chan int)
ch <- t.Value
if t.Left != nil {
go Walk(t.Left, temp1)
}
if t.Right != nil {
go Walk(t.Right, temp2)
}
if t.Left != nil {
for i := range temp1 {
ch <- i
}
}
if t.Right != nil {
for i := range temp2 {
ch <- i
}
}
close(ch)
}
// Same determines whether the trees
// t1 and t2 contain the same values.
func Same(t1, t2 *tree.Tree) bool
func main() {
var ch chan int = make(chan int)
go Walk(tree.New(1), ch)
for i := range ch {
fmt.Println(i)
}
}
So I did this by by sending in a flag into the Walk function. This way it knows when it can close down the channel. I also think it's important to walk the tree in the right order Left node, Value, Right node.
package main
import (
"fmt"
"tour/tree"
)
// Walk walks the tree t sending all values
// from the tree to the channel ch.
func Walk(t *tree.Tree, c chan int, d bool) {
if t.Left != nil {
Walk(t.Left, c, false)
}
c <- t.Value
if t.Right != nil {
Walk(t.Right, c, false)
}
if d {
close(c)
}
}
// Same determines whether the trees
// t1 and t2 contain the same values.
func Same(t1, t2 *tree.Tree) bool {
ch1 := make(chan int)
ch2 := make(chan int)
go Walk(t1, ch1, true)
go Walk(t2, ch2, true)
for {
v1, ok1 := <-ch1
v2, ok2 := <-ch2
if v1 != v2 {
return false
}
if ok1 != ok2 {
return false
}
if !ok1 && !ok2 {
return true
}
}
return false
}
func main() {
ch := make(chan int)
go Walk(tree.New(1), ch, true)
for i := range ch {
fmt.Println(i)
}
test1 := Same(tree.New(1), tree.New(1))
test2 := Same(tree.New(1), tree.New(2))
fmt.Println(test1, test2)
}

Resources