Go的缓冲通道本质上是一个线程安全的FIFO队列。 (见Is it possible to use Go's buffered channel as a thread-safe queue?)
我想知道它是如何实施的。它是否像Is there such a thing as a lockless queue for multiple read or write threads?中描述的那样无锁?
在Go的src目录(grep -r Lock .|grep chan
)中进行greping会得到以下输出:
./pkg/runtime/chan.c: Lock;
./pkg/runtime/chan_test.go: m.Lock()
./pkg/runtime/chan_test.go: m.Lock() // wait
./pkg/sync/cond.go: L Locker // held while observing or changing the condition
虽然不能锁定我的机器(MacOS,intel x86_64)。有没有官方资源来验证这个?
答案 0 :(得分:6)
如果您阅读chan.c中的runtime·chansend
功能,则会在检查之前看到runtime·lock
被调用,以查看频道是否已缓存if(c->dataqsiz > 0)
。
换句话说,缓冲通道(以及一般所有通道)都使用锁。
您的搜索没有找到它的原因是您正在寻找带有大写字母L的“锁定”。用于通道的锁定函数是运行时中的非导出C函数。
答案 1 :(得分:4)
您可以为您喜欢的任何内容编写无锁(甚至无需等待!)的实现。像CMPXCHG这样的现代硬件原型足以普遍使用。但编写和验证此类算法并不是最简单的任务之一。除此之外,可能存在更快的算法:无锁算法通常只是算法的一小部分。
据我所知,Dmitry Vyukov过去为Go编写了一个无锁的MPMC(多重生产者/多用户)频道实现,但由于Go的select语句存在一些问题,该补丁被放弃了。有效地支持这种说法似乎非常困难。
然而,Go的通道类型的主要目标是提供一个高级并发原语,可以轻松地用于各种各样的问题。即使不是并发编程专家的开发人员也应该能够编写正确的程序,这些程序可以在较大的软件项目中轻松查看和维护。如果您有兴趣挤出最后一点性能,则必须编写一个适合您需求的专用队列实现。