Go通道无缓冲

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

Go channels unbuffered

问题

我来帮你翻译一下代码和问题:

package main
import (
    "fmt"
    "time"
)

var message chan string

func main() {
    message = make(chan string)
    count := 6
    flag := "first"
    go func() {
        fmt.Println("子 goroutine ", flag)
        for i := 0; i < count; i++ {
            fmt.Println("设置:", i)
            message <- fmt.Sprintf("消息 %d", i)
        }   
    }()

    time.Sleep(time.Second * 0)

    fmt.Println("主 goroutine ", flag)
    flag = "last"
    for i := 0 ; i < count; i++ {
        fmt.Println("获取:", i)
        fmt.Println(<-message)
    }
}

我运行了这段代码,结果如下:

主 goroutine  first
获取: 0
子 goroutine  last
设置: 0
设置: 1
消息 0
获取: 1
消息 1
获取: 2
设置: 2
设置: 3
消息 2
获取: 3
消息 3
获取: 4
设置: 4
设置: 5
消息 4
获取: 5
消息 5

我对结果感到困惑。为什么在 "获取: 1" 之后出现了 "消息 1",而不是 "设置: 2"?这个问题困扰了我好几天!

我认为当执行到 "获取: 1" 时,主 goroutine 应该被阻塞,子 goroutine 应该被执行,将 "消息 1" 发送到 message 通道,并继续执行 for 循环并打印 "设置: 2",然后在发送 "消息 2" 到通道时被阻塞,所以主 goroutine 开始运行,输出 "消息 1"。

英文:
package main 
import (
	&quot;fmt&quot;
	&quot;time&quot;
)

var message chan string

func main() {
	message = make(chan string)
	count := 6
	flag := &quot;first&quot;
	go func() {
		fmt.Println(&quot;child go &quot;,flag)
		for i := 0; i &lt; count; i++ {
			fmt.Println(&quot;set:&quot;,i)
			message &lt;- fmt.Sprintf(&quot;message %d&quot;,i)
		}	
	}()

	time.Sleep(time.Second * 0)

	fmt.Println(&quot;main thread &quot;,flag)
	flag = &quot;last&quot;
	for i := 0 ; i &lt; count; i++ {
		fmt.Println(&quot;get:&quot;,i)
		fmt.Println(&lt;-message)
	}
}

I run the code and the result is:

main thread  first
get: 0
child go  last
set: 0
set: 1
message 0
get: 1
message 1
get: 2
set: 2
set: 3
message 2
get: 3
message 3
get: 4
set: 4
set: 5
message 4
get: 5
message 5

I am confused by the result. Why does 'message 1' appear after 'get 1' but not 'set 2'? This has puzzled me for several days!

I think when it 'get 1', the main go routine should be blocked and the child go routine should be exec'd, send 'message 1' to channel message and continue the for loop and print 'set 2',thus blocked at send 'message 2' to channel, so main go routine start to run, output 'message 1'.

答案1

得分: 1

代码的功能与你所想的一样(如果我理解你的意思的话):从message接收块直到收到一个值。不幸的是,在发送到通道之前,你的代码会打印“set 2”,而这个操作不会被阻塞。

同步只发生在<-处,通道发送之前的Println可以运行。
请查看http://play.golang.org/p/d6_SkBugqs,它在每次发送/接收操作之前和之后打印内容,你会看到所有的操作都被正确同步:所有的“post-recv n”都发生在“pre-send n”之后。

英文:

The code does exactly what you think it should do (if I understand what you think it should do): Receiving from message blocks until a value was sent. Unfortunately your code prints "set 2" before sending on the channel and this operation is not blocked.

Synchronisation happens only at &lt;-, the Println before the channel send can run.
Have a look at http://play.golang.org/p/d6_SkBugqs which prints before and after each send/receive op and you'll see that all is properly sycronised: All "post-recv n" happen after "pre-send n".

huangapple
  • 本文由 发表于 2014年7月28日 17:17:19
  • 转载请务必保留本文链接:https://go.coder-hub.com/24992008.html
匿名

发表评论

匿名网友

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

确定