在(简要)回顾Go语言规范,有效Go和Go内存模型之后,我仍然不清楚Go渠道如何在幕后工作。
他们是什么样的结构?它们的行为类似于线程安全的队列/数组。
他们的实施是否依赖于架构?
答案 0 :(得分:69)
频道的源文件是(来自你的源代码根目录)/src/pkg/runtime/chan.go。
hchan
是通道的中央数据结构,具有发送和接收链接列表(保存指向其goroutine和数据元素的指针)和closed
标志。在runtime2.go中定义了一个Lock
嵌入式结构,它可以作为互斥锁(futex)或信号量,具体取决于操作系统。锁定实现在lock_futex.go(Linux / Dragonfly / Some BSD)或lock_sema.go(Windows / OSX / Plan9 / Some BSD)中,基于构建标记。
频道操作都在这个chan.go文件中实现,因此你可以看到makechan,send和receive操作,以及select构造,close,len和cap内置函数。
要对频道的内部运作进行深入的解释,你必须阅读Dmitry Vyukov自己的Go channels on steroids(Go core dev,goroutines,scheduler and channels等)。
答案 1 :(得分:1)
以下是一个很好的演讲,大致描述了渠道的实现方式:
https://youtu.be/KBZlN0izeiY
对话说明:
GopherCon 2017:Kavya Joshi-了解频道
通道为goroutine进行通信提供了一种简单的机制,并为构建复杂的并发模式提供了强大的结构。我们将深入研究通道和通道操作的内部工作原理,包括运行时调度程序和内存管理系统如何支持它们。
答案 2 :(得分:0)
查看通道的一种更简单的方法是,您可能希望在等待条件完成时暂停程序,通常用于防止 RACE 条件,这意味着一个线程可能不会在另一个线程之前完成,并且那么您稍后的线程或代码所依赖的某些内容有时不会完成。 一个例子可能是,您有一个线程从数据库或其他服务器检索一些数据并将数据放入变量、切片或映射中,但由于某种原因它会被延迟。那么您就有一个使用该变量的进程,但由于它尚未初始化,或者尚未获得其数据。程序失败。 所以一个简单的看代码的方式如下: 包主
import "fmt"
var doneA = make(chan bool)
var doneB = make(chan bool)
var doneC = make(chan bool)
func init() { // this runs when you program starts.
go func() {
doneA <- true //Give donA true
}()
}
func initB() { //blocking
go func() {
a := <- doneA //will wait here until doneA is true
// Do somthing here
fmt.Print(a)
doneB <- true //State you finished
}()
}
func initC() {
go func() {
<-doneB // still blocking, but dont care about the value
// some code here
doneC <- true // Indicate finished this function
}()
}
func main() {
initB()
initC()
}
所以希望这会有所帮助。不是上面选择的答案,但我相信应该有助于消除谜团。我想知道我是否应该提出问题并自行回答?