Receiving values from channels in Go - 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.

Related

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).

Invoke async operation with result

Can you provide a pattern of how to invoke method async with result?
is there any best practice to invoke it by configuration sync/async
The keyword you have to search for is goroutines
Here is one example: https://gobyexample.com/goroutines
If you follow the tutorial, channels, buffered channels and syncronized channels will give you some way to return data.
Example 2: https://tour.golang.org/concurrency/1
Example 3: http://www.golangbootcamp.com/book/concurrency
TL;DR: Here is your pattern:
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)
}

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?

gooroutine is have a priority or not?

Golang fish,Seeking explanation.
Goroutine is have a priority or not?
package main
import (
"fmt"
)
func sum(a []int, c chan int) {
var total int
for _, v := range a {
total += v
}
c <- total
}
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
x := <-c
y := <-c
fmt.Println(x, y, x+y)
}
why the x is -5 y is 17,is not the first goroutine blocked?
if
go sum(a[:len(a)/2], c)
x := <-c
go sum(a[len(a)/2:], c)
y := <-c
this order is right. why。。。
In your first example, the output should be either -5 17 12 or 17 -5 12. Both goroutines are running concurrently (at the same time). The result of whichever goroutine finishes first will be stored in the variable x. The result of the other goroutine is stored in y. In order to better see that the goroutines are running concurrently, you can put a random timer inside the function sum(). This way, you should see the output change between different runs, because one goroutine randomly takes longer than the other:
package main
import (
"fmt"
"time"
"math/rand"
)
func sum(a []int, c chan int) {
time.Sleep(time.Duration(rand.Intn(1000000))) // wait for up to 1ms
total := 0
for _, v := range a {
total += v
}
c <- total
}
func main() {
rand.Seed(time.Now().Unix())
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 := <-c
y := <-c
fmt.Println(x, y, x+y)
}
In your second example, you are starting the first goroutine. Then you read from the channel c, which is a blocking operation (meaning it will wait until there's a result => the first goroutine is done). The output here is deterministic and will always be 17 -5 12.

goroutine out put to channel order fixed?

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).

Resources