goroutine out put to channel order fixed? - go

package main
import "fmt"
func sum(a []int, c chan int) {
sum := 0
for _, v := range a {
sum += v
}
c <- sum // send sum to c
}
func main() {
a := []int{7, 2, 8, -9, 4, 0}
c := make(chan int)
go sum(a[len(a)/2:], c)
go sum(a[:len(a)/2], c)
x, y := <-c, <-c // receive from c
fmt.Println(x, y, x+y)
}
x, y := <-c, <-c // receive from c
Why does this line always print the same result?
I think it should be 50/50 chance to print
17 -5 12
or
-5 17 12
I think the two go routines should be parallel
Thanks in advance!
package main
import "fmt"
import "time"
import "math/rand"
func sum(a []int, c chan int) {
sum := 0
for _, v := range a {
sum += v
}
time.Sleep(time.Millisecond * time.Duration(rand.Intn(1000)))
c <- sum // send sum to c
}
func main() {
a := []int{7, 2, 8, -9, 4, 0}
c := make(chan int)
go sum(a[len(a)/2:], c)
go sum(a[:len(a)/2], c)
x, y := <-c, <-c // receive from c
fmt.Println(x, y, x+y)
}
I make the thread to sleep, but same thing happens. I am still confusing.

The assumption that it should be a 50/50 chance is incorrect in this situation. To be clear, I'm not suggesting it should always be one or the other but rather that you shouldn't expect it to change each time the program runs. The behavior is not necessarily random (or even pseudo-random).
A goroutine's guarantee is not that it will be scheduled at a random future time, but rather just that it will run at some time in the future. If the current implementation of the scheduler decided to put goroutines in a simple queue, it wouldn't automatically mean it's broken. For your particular code's case, if you stick a few time.Sleeps or fmt.Printfs in different places, you'd likely see the order change around sometimes.
I wonder if you're confusing Go's scheduler's selection of the next goroutine with the documented pseudo-random behavior of select when used with channels. The behavior there is defined to be random and it's correct to say the behavior should have a 50/50 chance.
As far as I've read, the choice of which goroutine the runtime will select is not random. That's not the same as saying it can't be random, but moreso that it's not supposed to be random.
The important thing is that your code shouldn't care about the order in which goroutines are scheduled. Whether it's always in order like a queue, or backwards (a stack), or random, or something else (likely the reality).

Related

Order while using channels

I have this code from Go tour:
func sum(s []int, c chan int) {
sum := 0
for _, v := range s {
sum += v
}
fmt.Printf("Sending %d to chan\n", sum)
c <- sum // send sum to c
}
func main() {
s := []int{2, 8, -9, 4, 0, 99}
c := make(chan int)
go sum(s[len(s)/2:], c)
go sum(s[:len(s)/2], c)
x, y := <-c, <-c // receive from c
fmt.Println(x, y, x+y)
}
Produces this output:
Sending 1 to chan
Sending 103 to chan
1 103 104
In this, x gets the second sum and y gets the first sum. Why is the order reversed?
Similar to goroutines order of execution
If you run it multiple times, it may give different result. When I run this I get:
Sending 103 to chan
Sending 1 to chan
103 1 104
If you want result to be deterministic. You may use two channels:
func main() {
s := []int{2, 8, -9, 4, 0, 99}
c1 := make(chan int)
c2 := make(chan int)
go sum(s[len(s)/2:], c1)
go sum(s[:len(s)/2], c2)
x, y := <-c1, <-c2 // receive from c
fmt.Println(x, y, x+y)
}
There are no guarantees in the execution ordering of goroutines. When you start multiple goroutines, they may or may not execute in the order you expect them unless there are explicit synchronizations between them, such as channels or other synchronization primitives.
In your case, the second goroutine writes the channel before the first can, because there is no mechanism to enforce ordering between the two goroutines.
The golang spec says about the channels:
Channels act as first-in-first-out queues. For example, if one
goroutine sends values on a channel and a second goroutine receives
them, the values are received in the order sent.
If you combine the above statement with the arbitrary order of the goroutines execution it could lead to arbitrary order of enqueuing items to channel.
NB: A channel is an abstraction of the CSP.

Receiving values from channels in Go

Why doesn't the last result returned from go sum(s[len(s)/2:], c)(the second one) be assigned to x?
The two <-cs confuse me.
This code is from A Tour of Go - [Channels].
package main
import "fmt"
func sum(s []int, c chan int) { // int is the return value type
sum := 0
for _, v := range s {
sum += v
}
c <- sum // Sends sum to c
}
func main() {
s := []int{7, 2, 8, -9, 4, 0}
c := make(chan int)
go sum(s[:len(s)/2], c)
go sum(s[len(s)/2:], c)
x, y := <-c, <-c // receive from c
fmt.Println(x, y, x+y)
}
Do you mean this line?
x, y := <-c, <-c
That's a "tuple assignment".
In this case, it would be equivalent to doing:
x := <-c
y := <-c
So the second value read from c would be assigned to y.
You can read more about it here:
https://golang.org/ref/spec#Assignments
About the order in which the values are actually written to c, since two independent goroutines are being triggered here:
go sum(s[:len(s)/2], c)
go sum(s[len(s)/2:], c)
The order in which they end up processing and writing to c is not "guaranteed", so you can expect either one of the values be assigned to x and y in different runs.
Since the values are being added to calculate the final result, this is not a problem in this case.

understand go unbuffered channel example

official code example
func sum(s []int, c chan int) {
sum := 0
for _, v := range s {
sum += v
}
c <- sum // send sum to c
}
func main() {
s := []int{7, 2, 8, -9, 4, 0}
c := make(chan int)
go sum(s[:len(s)/2], c)
go sum(s[len(s)/2:], c)
x := <-c
y := <-c
fmt.Println(x, y, x+y)
}
printed : -5, 17, 12
why not printed 17, -5, 12 ?
I think x should be 17
There's no defined order of which value gets written to the channel first, it's purely at the mercy of the scheduler. As all the example is doing is adding the results, it doesn't actually matter which way round the results turn up.
There is no guarantee in what order your go sum(...) goroutines will start and which will be the first to finish (and send to channel).

get unexpect datas from channel using goroutine

A piece of code from tutorials on tour.golang.org
package main
import "fmt"
func sum(s []int, c chan int) {
sum := 0
for _, v := range s {
sum += v
}
c <- sum // send sum to c
}
func main() {
s := []int{7, 2, 8, -9, 4, 0}
c := make(chan int)
go sum(s[:len(s)/2], c) //give 17
go sum(s[len(s)/2:], c) //give -5
x, y := <-c, <-c // receive from c
fmt.Println(x, y, x+y)
}
The output result is always -5 17 12 which means the first goroutine is stably behind the second. As my understanding to multithreading and channel, the order of result should be the opposite in this simple context.When the goroutine's task become more complexed the order should be unexpectable.So how to explain this LIFO like issue?

Go lang, channel processing sequence

I'm studying Go lang through 'A tour of Go', and it's hard to understand Go channel running sequence,
package main
import "fmt"
import "time"
func sum(a []int, c chan int) {
sum := 0
for _, v := range a {
time.Sleep(1000 * time.Millisecond)
sum += v
}
c <- sum // send sum to c
}
func main() {
a := []int{7, 2, 8, -9, 4, 0}
c := make(chan int)
go sum(a[:len(a)/2], c)
go sum(a[len(a)/2:], c)
x, y := <-c, <-c // receive from c
fmt.Println(x, y, x+y)
fmt.Println("Print this first,")
}
If run above the code, I expected,
Print this first,
17 -5 12
Because, Go routine runs as non-blocking, a But, actually it prints,
17 -5 12
Print this first,
The other example that I found in internet,
package main
import "fmt"
type Data struct {
i int
}
func func1(c chan *Data ) {
fmt.Println("Called")
for {
var t *Data;
t = <-c //receive
t.i += 10 //increment
c <- t //send it back
}
}
func main() {
c := make(chan *Data)
t := Data{10}
go func1(c)
println(t.i)
c <- &t //send a pointer to our t
i := <-c //receive the result
println(i.i)
println(t.i)
}
Also, I expected, it prints "Called" first, but the result is
10
20
20
Called
What I am misunderstanding? please help me to understand Go routine and channel.
In your first example, x, y := <-c, <-c will block until it reads off c twice, and then assign values to x, y. Channels aside, you have an assignment, a print statement, then another print statement. Those are all synchronous things, and will happen in the order you state them in. There's no way the second print statement would print first.
The second one is because fmt.Println writes to STDOUT and println to STDERR. If you are consistent (say use println everywhere) then you see:
10
Called
20
20
That's cause there's a race between the first println(t.i) in the main and the println("Called") that's happening in the goroutine. I'm guessing with GOMAXPROCS set to 1, this will happen consistently. With GOMAXPROCS set to NumCPU, I get a mix of results, sometimes looking like the above, and sometimes like this:
10Called
20
20

Resources