在Go语言的select语句中,发送操作和接收操作之间有一定的优先规则。

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

priority rule between sent and receive operation in a go select statement

问题

在Go语言的select语句中,发送操作和接收操作之间有优先规则吗?

由于“发送”操作总是准备就绪,不像“接收”操作需要等待通道中的数据到达,我一直有一种感觉,即在select语句中,“发送”操作会先执行。

我尝试了一小段代码来测试当发送和接收操作都准备就绪时会发生什么:

package main

import (
	"fmt"
	"time"
)

func main() {
	ch1 := make(chan string)
	ch2 := make(chan string)
	go goOne(ch1)
	go goTwo(ch2)

	time.Sleep(time.Second * 2)
	select {
	case ch2 <- "To goTwo goroutine":
	case msg1 := <-ch1:
		fmt.Println(msg1)
	}
}

func goOne(ch chan string) {
	ch <- "From goOne goroutine"
}

func goTwo(ch chan string) {
	msg := <-ch
	fmt.Println(msg)
}

结果似乎总是打印“From goOne goroutine”。所以看起来接收操作具有优先级。
但这是设计上的效果吗?还是可能发生发送操作先执行的情况?我在文档中找不到相关信息。

如果我希望接收操作具有优先级,我可以依赖这一点吗?还是应该采取其他措施?

谢谢!

英文:

Is there a priority rule between sent and receive operation in a go select statement ?

Since a "send" operation is always ready, not like a "receive" operation that wait for something to come from the channel, I always have the feeling that the "send" will be executed first on a select.

I tried a little code to test what happens when both send and receive are ready:

package main

import (
	&quot;fmt&quot;
	&quot;time&quot;
)

func main() {
	ch1 := make(chan string)
	ch2 := make(chan string)
	go goOne(ch1)
	go goTwo(ch2)

	time.Sleep(time.Second * 2)
	select {
	case ch2 &lt;- &quot;To goTwo goroutine&quot;:
	case msg1 := &lt;-ch1:
		fmt.Println(msg1)
	}
}

func goOne(ch chan string) {
	ch &lt;- &quot;From goOne goroutine&quot;
}

func goTwo(ch chan string) {
	msg := &lt;-ch
	fmt.Println(msg)
}

The result seems to always be "From goOne goroutine". So it seems the receive operation has the priority.
But is it by design effect ? Or could it happen that the sent got executed first? I couldn't find the info in the doc

If I want the receive operation to have the priority, can I rely on that or should I do something else ?

Thanks!

答案1

得分: 2

在go的select语句中,发送操作和接收操作之间没有优先规则。当多个case同时准备好时,会随机选择一个执行。

关于“发送”操作总是准备好的说法是不正确的。当另一端没有接收时,或者缓冲通道的缓冲区已满时,发送操作可能会被阻塞(即不准备好)。

关于发送操作是否可能先执行的问题,是的,但是当选择这个case时,你可能看不到任何输出,因为在goTwo goroutine实际打印任何内容之前,你的程序会在主函数中恢复执行并立即退出。

如果你希望接收操作具有优先级[...],select语句的语义是:“执行首先准备好的操作”。如果一个case必须优先于另一个case,将另一个case改为default(当没有其他case准备好时执行):

select {
case msg1 := <-ch1:
    fmt.Println(msg1)
default:
    ch2 <- "To goTwo goroutine"
}
英文:

> Is there a priority rule between sent and receive operation in a go select statement?

No. When more than one case is ready at the same time, one at random is executed.

> Since a "send" operation is always ready

Not true. A send operation may just block (i.e. not ready) when nothing is receiving on the other side, or when a buffered channel's buffer is full.

> Or could it happen that the sent got executed first?

Yes, but you may see no output when this case is selected because your program resumes execution in main and exits immediately before the goTwo goroutine can actually print anything.

> If I want the receive operation to have the priority [...]

The very semantics of a select statement are: "execute whichever is ready first". If one case must have priority over the other, change the other one to default (runs if nothing else is ready):

    select {
    case msg1 := &lt;-ch1:
        fmt.Println(msg1)
    default:
        ch2 &lt;- &quot;To goTwo goroutine&quot;
    }

huangapple
  • 本文由 发表于 2022年3月1日 21:36:17
  • 转载请务必保留本文链接:https://go.coder-hub.com/71309314.html
匿名

发表评论

匿名网友

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

确定