golang: strange issue with coroutines and channels - go

I wrote a test code, but do not understand why I get this result.
My sub() should update or return counter, based on the channel value
send 1 = counter++
send 0 = return counter
I start 10 go routines con().
They should simply send many 1 to channel (this increase counter)
I wait 1 sec and send 0 to channel. What value should I get?
I think first, I get a "random" value,
but i get 100000 (ok 10x 10000 is faster than 1 sec)
Now I change
for i:=0; i < 10; i++ {
to
for i:=0; i < 10000; i++ {
and now my returned value is 1
Why!?
Now uncomment fmt.Println(counter) in main().
As you see counter works and has this "random" number
package main
import (
"fmt"
"time"
)
var ch chan int = make(chan int)
var counter int
func main() {
go sub()
for i:=0; i < 10; i++ { //change to 10000
go con()
}
time.Sleep(1000 * time.Millisecond)
ch <- 0
fmt.Println(<- ch)
//fmt.Println(counter) //uncomment this
}
func sub() {
for c := range ch {
if c == 0 { ch <- counter }
if c == 1 { counter++ }
}
}
func con() {
for i := 0; i < 10000; i++ {
ch <- 1
}
}

with 2 channels, this work:
package main
import (
"fmt"
"time"
)
var ch chan int = make(chan int)
var ch2 chan int = make(chan int)
var counter int
func main() {
go sub()
for i:=0; i < 10000; i++ { //change to 10000
go con()
}
time.Sleep(1000 * time.Millisecond)
ch2 <- 0
fmt.Println(<- ch2)
//fmt.Println(counter) //uncomment this
}
func sub() {
for ;; {
select {
case <- ch:
counter++
case <- ch2:
ch2 <- counter
}
}
}
func con() {
for i := 0; i < 10000; i++ {
ch <- 1
}
}

Related

go concurrency prints serially

i am trying to print concurrently but not able to figure out why its serial, have put the code below
package main
import (
"fmt"
"sync"
)
func main() {
fmt.Println("Hello, playground")
var wg sync.WaitGroup
wg.Add(2)
go func(){
for i := 0; i < 4; i++ {
if i%2 == 0 {
fmt.Println("hi", i)
}
}
wg.Done()
}()
go func() {
for i := 0; i < 4; i++ {
if i%2 != 0 {
fmt.Println("g", i)
}
}
wg.Done()
}()
wg.Wait()
}
expectation is
hi0
g1
hi2
g3
but i get
from g 1
from g 3
hi 0
hi 2
Such a small function is less likely to demonstrate the concurrency, because the first goroutine may complete even before the second one starts, or before context switch happens. If you add a small pause to the loop, you will observe the interleaving:
package main
import (
"fmt"
"sync"
"time"
)
func main() {
var wg sync.WaitGroup
wg.Add(2)
go func() {
for i := 0; i < 4; i++ {
if i%2 == 0 {
fmt.Println("hi", i)
}
time.Sleep(10 * time.Millisecond)
}
wg.Done()
}()
go func() {
for i := 0; i < 4; i++ {
if i%2 != 0 {
fmt.Println("from g", i)
}
time.Sleep(10 * time.Millisecond)
}
wg.Done()
}()
wg.Wait()
}

goruntine not running concurrently?

I have the following program, I am new to gorountine, what I want to test is simple, I am calling a gorountine in a loop 100 times, it there is one time failure, the entire program fails, otherwise succeeds, and fail10Percent it delays 1 second, and check a random number if it is 4, let it fail.
package main
import (
"fmt"
"math/rand"
"time"
)
func fail10Percent(ch chan int) {
time.Sleep(1 * time.Second)
e := rand.Intn(10)
fmt.Println("Calculating rand.Intn(10) ", e)
if e == 4 {
ch <- 0
return
}
ch <- 1
}
func test() {
for i := 0; i < 100; i++ {
err := make(chan int)
go fail10Percent(err)
res := <-err
fmt.Println("=== result: ", res)
if res != 1 {
fmt.Println("failed")
return
}
}
fmt.Println("succeeded")
}
func main() {
test()
}
I expect the go fail10Percent(err) will run concurrently 100 times, which will only have 1 second delay, however, when I run it, I see the following result getting printed 1 second after 1 second, why is that, and how I can adjust my program to do what I want.
Calculating rand.Intn(10) 1
=== result: 1
Calculating rand.Intn(10) 7
=== result: 1
Calculating rand.Intn(10) 7
=== result: 1
Calculating rand.Intn(10) 9
=== result: 1
Calculating rand.Intn(10) 1
=== result: 1
Calculating rand.Intn(10) 8
=== result: 1
Calculating rand.Intn(10) 5
=== result: 1
Calculating rand.Intn(10) 0
=== result: 1
Calculating rand.Intn(10) 6
=== result: 1
Calculating rand.Intn(10) 0
=== result: 1
Calculating rand.Intn(10) 4
=== result: 0
failed
I've commented out the code for you so that you can understand.
package main
import (
"fmt"
"math/rand"
"sync"
)
func fail10Percent(ch chan int, w *sync.WaitGroup) {
defer w.Done()
num := rand.Intn(10)
fmt.Println("calculating rand.Intn(10) ", num)
if num == 4 {
ch <- 0 // Fail
return
}
ch <- 1 // Pass
}
func test() {
var ch = make(chan int, 1)
// Launch the receiver goroutine to listen if goroutine succeeded or failed based on the value sent to ch
go func() {
for recv := range ch {
switch recv {
// Fail
case 0:
fmt.Println("goroutine failed")
// Pass
case 1:
fmt.Println("goroutine succeed")
}
}
}()
// wg is a WaitGroup
var wg sync.WaitGroup
for i := 0; i < 100; i++ {
wg.Add(1)
go fail10Percent(ch, &wg)
}
// wg.Wait() to wait for all goroutines to complete
wg.Wait()
// Close the channel so that the receiver can stop
close(ch)
}
func main() {
test()
}
Update:
Simple solution without using sync.WaitGroup
package main
import (
"fmt"
"math/rand"
)
// Using a send only channel
func fail10Percent(ch chan<- int) {
num := rand.Intn(10)
fmt.Println("calculating rand.Intn(10) ", num)
if num == 4 {
ch <- 0 // Fail
return
}
ch <- 1 // Pass
}
func test() {
var ch = make(chan int, 1)
for i := 0; i < 100; i++ {
go fail10Percent(ch)
}
for i := 0; i < 100; i++ {
if recv := <-ch; recv == 0 {
fmt.Println("goroutine failed")
} else if recv == 1 {
fmt.Println("goroutine succeed")
}
}
close(ch)
}
func main() {
test()
}

Passing info from channel to channel while altering it in go

I'm new to the go programming language.
I just learned about channels from their website, and tried to create
The following program:
1) I want to create 100,000 channels.
2) when the first channel receives a msg (value) he adds 1 to it
and pass it on to the next channel (by order).
3) when we'll get to the last channel it Will print 100,001.
I have created the channels with a loop, but I find it difficult to find
how to pass and alter the data in a "domino" fashion like I described.
Any solution or reference would be appreciated.
Thanks!
Here is my code:
package main
func addOneAndPass(c1 chan int, c2 chan int) {
c := make(chan int)
c <- 1
val := <- c
}
func main() {
const n = 100000
var channels [n]chan int
for i := 0; i < n; i++ {
channels[i] = make(chan int)
}
}
https://play.golang.org/p/ku-Dretm8EA
package main
import (
"fmt"
)
func add1(in chan int) (chan int) {
i := <-in
out := make(chan int, 1)
out <- (i+1)
return out
}
func main() {
ch := make(chan int, 1)
ch <- 1
for i := 0; i < 100000; i++ {
ch = add1(ch)
}
fmt.Println(<-ch)
}
another solution: https://play.golang.org/p/uWVxSG0xgqU
package main
import (
"fmt"
)
func add1(in, out chan int) {
i := <-in
out <- (i+1)
}
func main() {
start := make(chan int)
var in = start
var ch chan int
for i := 0; i < 100000; i++ {
ch = make(chan int)
go add1(in, ch)
in = ch
}
start <- 1
fmt.Println(<-ch)
}

Why the result is not as expected with flag "-race"?

Why the result is not as expected with flag "-race" ?
It expected the same result: 1000000 - with flag "-race" and without this
https://gist.github.com/romanitalian/f403ceb6e492eaf6ba953cf67d5a22ff
package main
import (
"fmt"
"runtime"
"sync/atomic"
"time"
)
//$ go run -race main_atomic.go
//954203
//
//$ go run main_atomic.go
//1000000
type atomicCounter struct {
val int64
}
func (c *atomicCounter) Add(x int64) {
atomic.AddInt64(&c.val, x)
runtime.Gosched()
}
func (c *atomicCounter) Value() int64 {
return atomic.LoadInt64(&c.val)
}
func main() {
counter := atomicCounter{}
for i := 0; i < 100; i++ {
go func(no int) {
for i := 0; i < 10000; i++ {
counter.Add(1)
}
}(i)
}
time.Sleep(time.Second)
fmt.Println(counter.Value())
}
The reason why the result is not the same is because time.Sleep(time.Second) does not guarantee that all of your goroutines are going to be executed in the timespan of one second. Even if you execute go run main.go, it's not guaranteed that you will get the same result every time. You can test this out if you put time.Milisecond instead of time.Second, you will see much more inconsistent results.
Whatever value you put in the time.Sleep method, it does not guarantee that all of your goroutines will be executed, it just means that it's less likely that all of your goroutines won't finish in time.
For consistent results, you would want to synchronise your goroutines a bit. You can use WaitGroup or channels.
With WaitGroup:
//rest of the code above is the same
func main() {
counter := atomicCounter{}
var wg sync.WaitGroup
for i := 0; i < 100; i++ {
wg.Add(1)
go func(no int) {
for i := 0; i < 10000; i++ {
counter.Add(1)
}
wg.Done()
}(i)
}
wg.Wait()
fmt.Println(counter.Value())
}
With channels:
func main() {
valStream := make(chan int)
doneStream := make(chan int)
result := 0
for i := 0; i < 100; i++ {
go func() {
for i := 0; i < 10000; i++ {
valStream <- 1
}
doneStream <- 1
}()
}
go func() {
counter := 0
for count := range doneStream {
counter += count
if counter == 100 {
close(doneStream)
}
}
close(valStream)
}()
for val := range valStream {
result += val
}
fmt.Println(result)
}

Deadlock in Housie Program. Producer-Consumer Pattern

I am trying to implement a housie game where a goroutine produces numbers, 3 other goroutines check if these are in their tokens and inform the producer if all their numbers were produced. I have implemented it in golang in the following way. This results in a deadlock. Any idea why this is happening? This is a "homework problem", I am just implementing it in go to learn go better.
package main
import (
"fmt"
"math/rand"
)
type PersonID int
func contains(s []int, e int) bool {
for _, a := range s {
if a == e {
return true
}
}
return false
}
func Person(called_number chan int, claim_prize chan PersonID, received chan bool, coupon []int, person_id PersonID) {
numFound := 0
for i := 0; i < len(coupon); i++ {
current_number := <-called_number
found := contains(coupon, current_number)
if found {
numFound++
}
if numFound == len(coupon) {
claim_prize <- person_id
} else {
received <- true
}
}
}
func main() {
var called_number chan int
var claim_prize chan PersonID
var received chan bool
tokens := make([][]int, 3)
for i := 0; i < 3; i++ {
tokens[i] = make([]int, 12)
for j := 0; j < 12; j++ {
num := rand.Intn(100) + 1
found := contains(tokens[i], num)
for found {
num = rand.Intn(100) + 1
found = contains(tokens[i], num)
}
tokens[i][j] = num
}
}
go Person(called_number, claim_prize, received, tokens[0], 0)
go Person(called_number, claim_prize, received, tokens[1], 1)
go Person(called_number, claim_prize, received, tokens[2], 2)
claimants := make([]PersonID, 0)
prev_called := make(map[int]bool)
for i := 0; i < 100; i++ {
if len(claimants) == 3 {
break
}
num := rand.Intn(100) + 1
_, ok := prev_called[num]
for ok {
num = rand.Intn(100) + 1
_, ok = prev_called[num]
}
prev_called[num] = true
called_number <- num
for j := 0; j < 3; j++ {
select {
case _ = <-received:
continue
case pid := <-claim_prize:
claimants = append(claimants, pid)
}
}
}
fmt.Println(claimants)
}
EDIT:
The exact problem is that that the producer needs to send the number to each of the consumers. When a consumer receives all the numbers in it's token, it can claim the prize. Based on what #OneOfOne said, I have made some changes to the program. The changes are that now there is a separate channels for each of the consumers and I am closing it after it claims a prize. Below is the new program, it still deadlocks.
package main
import (
"fmt"
"math/rand"
)
func contains(s []int, e int) bool {
for _, a := range s {
if a == e {
return true
}
}
return false
}
func Person(called_number chan int, claim_prize chan int, received chan bool, coupon []int, person_id int) {
numFound := 0
for current_number := range called_number {
if contains(coupon, current_number) {
numFound++
}
if numFound == len(coupon) {
fmt.Println(person_id)
claim_prize <- person_id
} else {
received <- true
}
}
}
func main() {
var (
called_number1 = make(chan int, 1)
called_number2 = make(chan int, 1)
called_number3 = make(chan int, 1)
claim_prize = make(chan int, 1)
received = make(chan bool, 1)
)
tokens := make([][]int, 3)
for i := 0; i < 3; i++ {
tokens[i] = make([]int, 12)
for j := 0; j < 12; j++ {
num := rand.Intn(100) + 1
found := contains(tokens[i], num)
for found {
num = rand.Intn(100) + 1
found = contains(tokens[i], num)
}
tokens[i][j] = num
}
}
go Person(called_number1, claim_prize, received, tokens[0], 0)
go Person(called_number2, claim_prize, received, tokens[1], 1)
go Person(called_number3, claim_prize, received, tokens[2], 2)
claimants := make([]int, 0)
prev_called := make(map[int]bool)
for i := 0; i < 100; i++ {
if len(claimants) == 3 {
break
}
num := rand.Intn(100) + 1
_, ok := prev_called[num]
for ok {
num = rand.Intn(100) + 1
_, ok = prev_called[num]
}
prev_called[num] = true
if !contains(claimants, 0) {
called_number1 <- num
}
if !contains(claimants, 1) {
called_number2 <- num
}
if !contains(claimants, 2) {
called_number3 <- num
}
for j := 0; j < 3; j++ {
select {
case _ = <-received:
continue
case pid := <-claim_prize:
if pid == 0 { close(called_number1) }
if pid == 1 { close(called_number2) }
if pid == 2 { close(called_number3) }
claimants = append(claimants, pid)
}
}
}
fmt.Println(claimants)
}
EDIT2: This still deadlocked because I was not reducing the number of channels to wait for even after the goroutines were completed. Did that and everything works.
Few problems:
You're using a nil channel, so it just blocks forever, for some reason it's not panicing.
Also, your second inner loop will block indefinitely because it's waiting to read but nothing is being sent.
After your Person's loop ends, called_number <- num will block forever.
//edit
Kinda-working-code : http://play.golang.org/p/3At5nuJTuk
But the logic is flawed, you will have to rethink it.

Resources