英文:
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 (
"fmt"
"time"
)
var message chan string
func main() {
message = make(chan string)
count := 6
flag := "first"
go func() {
fmt.Println("child go ",flag)
for i := 0; i < count; i++ {
fmt.Println("set:",i)
message <- fmt.Sprintf("message %d",i)
}
}()
time.Sleep(time.Second * 0)
fmt.Println("main thread ",flag)
flag = "last"
for i := 0 ; i < count; i++ {
fmt.Println("get:",i)
fmt.Println(<-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 <-
, 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".
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论