Go的缓冲通道是否无锁?

Son*_*Gao 6 thread-safety go lockless

Go的缓冲通道本质上是一个线程安全的FIFO队列.(请参阅是否可以将Go的缓冲通道用作线程安全队列?)

我想知道它是如何实现的.它是无锁的,如有多个读或写线程的无锁队列吗?

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
Run Code Online (Sandbox Code Playgroud)

但是不要锁定我的机器(MacOS,intel x86_64).有没有官方资源来验证这个?

Ste*_*erg 7

如果您runtime·chansendchan.c中读取该函数,您将看到runtime·lock在检查之前调用该函数以查看该通道是否已缓冲if(c->dataqsiz > 0).

换句话说,缓冲通道(以及通常的所有通道)都使用锁.

您的搜索没有找到它的原因是您正在寻找带有大写字母L的"Lock".用于通道的锁定函数是运行时中的非导出C函数.


tux*_*21b 6

您可以为您喜欢的一切编写无锁(甚至无等待!)实现。像 CMPXCHG 这样的现代硬件原语足以普遍使用。但是编写和验证此类算法并不是最简单的任务之一。除此之外,可能存在更快的算法:无锁算法通常只是算法的一个很小的子集。

据我所知,Dmitry Vyukov 过去曾为 Go 编写了无锁 MPMC(多生产者/多消费者)通道实现,但由于 Go 的 select 语句存在一些问题,该补丁被放弃了。有效地支持这种说法似乎真的很难。

然而,Go 的通道类型的主要目标是提供一个高级并发原语,该原语易于用于解决广泛的问题。即使不是并发编程专家的开发人员也应该能够编写正确的程序,这些程序可以在大型软件项目中轻松审查和维护。如果您有兴趣挤出最后一点性能,您将不得不编写一个适合您需要的专门队列实现。