英文:
goroutine out put to channel order fixed?
问题
这行代码总是打印相同的结果,是因为在接收通道数据时,它是按顺序接收的。无论哪个goroutine先完成计算并发送数据到通道,都会先被接收到。所以无论是x, y := <-c, <-c
还是x, y := <-c, <-c
,结果都是一样的。
如果你希望两个goroutine并行执行,并且结果的顺序不确定,你可以使用带有缓冲区的通道。例如,将通道声明为c := make(chan int, 2)
,这样它就有一个缓冲区可以同时接收两个值。这样,两个goroutine可以并行地发送数据到通道,而不会被阻塞。然后,你可以按照你期望的顺序接收数据。
以下是修改后的代码示例:
package main
import (
"fmt"
"time"
"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, 2) // 带有缓冲区的通道
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)
}
这样修改后,你会发现结果的顺序可能会变化,因为两个goroutine可以并行地发送数据到通道。
英文:
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.
答案1
得分: 2
在这种情况下,假设应该是50/50的机会是错误的。明确地说,我并不是在暗示它应该总是一个或另一个,而是你不应该期望每次程序运行时都会改变。行为不一定是随机的(甚至不是伪随机的)。
一个goroutine的保证不是它将在将来的某个随机时间被调度,而只是它将在将来的某个时间运行。如果调度器的当前实现决定将goroutine放入一个简单的队列中,这并不意味着它是有问题的。对于你的特定代码情况,如果你在不同的地方插入一些time.Sleep
或fmt.Printf
,你可能会看到顺序有时会改变。
我想知道你是否将Go的调度器选择下一个goroutine的行为与在通道上使用select
时记录的伪随机行为混淆了。在那里的行为被定义为随机的,可以说这种行为应该有50/50的机会是正确的。
据我所读,运行时将选择哪个goroutine的选择并不是随机的。这并不意味着它不能是随机的,而是说它不应该是随机的。
重要的是,你的代码不应该关心goroutine被调度的顺序。无论是像队列一样按顺序,还是倒序(堆栈),或者是随机的,或者是其他什么(可能是现实)。
英文:
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.Sleep
s or fmt.Printf
s 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).
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论