英文:
Is Go's buffered channel lockless?
问题
Go的缓冲通道本质上是一个线程安全的先进先出队列。我想知道它是如何实现的。它是否像https://stackoverflow.com/questions/3020620/is-there-such-a-thing-as-a-lockless-queue-for-multiple-read-or-write-threads中描述的那样无锁?
在Go的src目录中使用grep -r Lock .|grep chan
命令得到以下输出:
./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),似乎没有锁。是否有官方资源可以验证这一点?
英文:
Go's buffered channel is essentially a thread-safe FIFO queue. (See https://stackoverflow.com/questions/10424144/is-it-possible-to-use-gos-buffered-channel-as-a-thread-safe-queue)
I am wondering how it's implemented. Is it lock-free like described in https://stackoverflow.com/questions/3020620/is-there-such-a-thing-as-a-lockless-queue-for-multiple-read-or-write-threads?
greping in Go's src directory (grep -r Lock .|grep chan
) gives following output:
./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
Doesn't to be locking on my machine (MacOS, intel x86_64) though. Is there any official resource to validate this?
答案1
得分: 8
如果你阅读chan.c中的runtime·chansend
函数,你会发现在检查通道是否有缓冲区if(c->dataqsiz > 0)
之前调用了runtime·lock
。
换句话说,有缓冲区的通道(以及所有通道)都使用锁。
你没有找到它的原因是你在搜索时使用了大写字母L的“Lock”。用于通道的锁函数是运行时中的一个非导出的C函数。
英文:
If you read the runtime·chansend
function in chan.c, you will see that runtime·lock
is called before the check to see if the channel is buffered if(c->dataqsiz > 0)
.
In other words, buffered channels (and all channels in general) use locks.
The reason your search did not find it was you were looking for "Lock" with a capital L. The lock function used for channels is a non-exported C function in the runtime.
答案2
得分: 7
你可以为任何你喜欢的东西编写无锁(甚至是无等待!)的实现。现代硬件原语如CMPXCHG足以普遍使用。但编写和验证这样的算法并不是最容易的任务之一。此外,可能存在更快的算法:无锁算法只是一般算法中的一个非常小的子集。
据我记得,Dmitry Vyukov曾经为Go编写了一个无锁的MPMC(多生产者/多消费者)通道实现,但该补丁被放弃了,因为Go的select语句存在一些问题。有效地支持这个语句似乎非常困难。
然而,Go的通道类型的主要目标是提供一个高级并发原语,可以轻松地用于各种问题。即使不是并发编程专家的开发人员也应该能够编写正确的程序,并且可以在更大的软件项目中轻松地进行审查和维护。如果你对提高性能感兴趣,你将不得不编写一个适合你需求的专门队列实现。
英文:
You can write lock-free (and even wait-free!) implementations for everything you like. Modern hardware primitives like CMPXCHG are enough to be universally usable. But writing and verifying such algorithms isn't one of the easiest tasks. In addition to that, much faster algorithms might exists: lock free algorithms are just a very small subset of algorithms in general.
As far as I remember, Dmitry Vyukov has written a lock-free MPMC (mutli-producer/multi-consumer) channel implementation for Go in the past, but the patch was abandoned, because of some problems with Go's select statement. Supporting this statement efficiently seems to be really hard.
The main goal of Go's channel type is however, to provide a high-level concurrency primitive that is easily usable for a broad range of problems. Even developers who aren't experts at concurrent programming should be able to write correct programs that can be easily reviewed and maintained in larger software projects. If you are interested in squeezing out every last bit of performance, you would have to write a specialized queue implementation that suits your needs.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论