我是Go的新手,并且在使用Go版本1.2在Linux上运行的代码块非常小的情况下,我感到难以接受。
基本上,我为int
创建一个通道,启动一个go例程来从通道读取,然后将一个int写入通道。
package main
import "fmt"
func main() {
channel := make(chan int)
go func() {
number := <- channel
fmt.Printf("GOT IT: %d\n", number)
}()
fmt.Println("[+] putting num on channel")
channel <- 42
fmt.Println("[-] putting num on channel")
}
大约90%的时间输出是预期的:
$ go run test.go
[+] putting num on channel
GOT IT: 42
[-] putting num on channel
然而,大约10%的时间,go例程根本不会从频道读取数字并且不打印任何内容:
$ go run test.go
[+] putting num on channel
[-] putting num on channel
我很困惑,因为这段代码非常类似于https://gobyexample.com/channels的例子(我没有这个问题),除了我在go例程中读取通道而不是写入渠道。
我是否对渠道的运作方式存在根本性的误解,或者在这里发挥了其他的作用?
答案 0 :(得分:6)
你应该等到你的goroutine执行,然后你的,例如,你可以用sync.WaitGroup
:
package main
import (
"fmt"
"sync"
)
func main() {
var wg sync.WaitGroup
channel := make(chan int)
wg.Add(1)
go func() {
number := <-channel
fmt.Printf("GOT IT: %d\n", number)
wg.Done()
}()
fmt.Println("[+] putting num on channel")
channel <- 42
wg.Wait()
fmt.Println("[-] putting num on channel")
}
(goplay:http://play.golang.org/p/VycxTw_4vu)
此外,您还可以使用“通知渠道”来表明作业已完成:
package main
import "fmt"
func main() {
channel := make(chan int)
done := make(chan bool)
go func() {
number := <-channel
fmt.Printf("GOT IT: %d\n", number)
done <- true
}()
fmt.Println("[+] putting num on channel")
channel <- 42
<-done
fmt.Println("[-] putting num on channel")
}
(goplay:http://play.golang.org/p/fApWQgtr4D)
答案 1 :(得分:3)
您似乎期望接收goroutine在第二个fmt.Println
执行之前运行完成。这不能保证是这种情况。如果程序终止,则不能保证goroutine到达其功能的末尾。
当您看到未显示“GOT IT”消息的输出时,频道发送了消息,但{goroutine之前完成了main
功能。程序终止,goroutine永远不会有机会拨打fmt.Printf
在您引用的示例中,main
函数以此结尾:
go func() { messages <- "ping" }()
msg := <-messages
fmt.Println(msg)
由于main
功能阻止接收消息,因此在此示例中,goroutine始终运行至完成。在你的代码中,你的goroutine在从通道接收后执行一个步骤,并且未定义goroutine或main函数是否会在接收后执行下一行。
答案 2 :(得分:2)
你有两个goroutines,一个在main()(隐含的是goroutine)和匿名的一个。
他们通过同步通道进行通信,因此在通道通信之后,保证它们是同步的。
此时,main()goroutine中的代码如下所示:
fmt.Println("[-] putting num on a channel")
并且匿名goroutine中留下的代码如下所示:
fmt.Println("GOT IT: %d\n", number)
现在你正在比赛:这些Println
的输出可能以任何顺序出现,甚至可能出现混合。当主要的Println()
完成时,该goroutine上发生的下一件事就是你的程序将被停止。这可能会阻止匿名goroutine中的部分或全部Println
出现。