【问题标题】:Is Go's buffered channel lockless?Go 的缓冲通道是无锁的吗?
【发布时间】:2012-10-17 15:51:05
【问题描述】:

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)。是否有任何官方资源可以验证这一点?

【问题讨论】:

    标签: thread-safety go lockless


    【解决方案1】:

    如果你阅读chan.c中的runtime·chansend函数,你会看到runtime·lock在检查通道是否被缓冲if(c->dataqsiz > 0)之前被调用。

    换句话说,缓冲通道(以及一般的所有通道)使用锁。

    您的搜索没有找到它的原因是您正在寻找带有大写 L 的“Lock”。用于通道的 lock 函数是运行时中未导出的 C 函数。

    【讨论】:

    • 谢谢!关于为什么它没有实现为无锁的任何想法?
    • "Lockfree" 并不意味着更好的性能。对锁进行推理也更容易。当竞争激烈时,Lock 方法可能更快。
    • 谢谢,@stephen-weinberg。现在这更有意义了。
    【解决方案2】:

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

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

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

    【讨论】:

      猜你喜欢
      • 2021-12-25
      • 2017-09-06
      • 2018-10-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-01-07
      • 1970-01-01
      • 2021-08-15
      相关资源
      最近更新 更多