协程输出到通道的顺序是否已经修复?

huangapple go评论86阅读模式
英文:

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 &quot;fmt&quot;

func sum(a []int, c chan int) {
	sum := 0
	for _, v := range a {
		sum += v
	}
	c &lt;- 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 := &lt;-c, &lt;-c // receive from c

	fmt.Println(x, y, x+y)
}

x, y := &lt;-c, &lt;-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 &quot;fmt&quot;
import &quot;time&quot;
import &quot;math/rand&quot;

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 &lt;- 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 := &lt;-c, &lt;-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.Sleepfmt.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.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).

huangapple
  • 本文由 发表于 2015年9月20日 12:49:28
  • 转载请务必保留本文链接:https://go.coder-hub.com/32675924.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定