golang select语句是如何实现的

How are golang select statements implemented?

本文关键字:实现 何实现 select 语句 golang      更新时间:2023-10-16

特别是,我在C++中有一些阻塞队列,我想等到其中任何一个有我可以弹出的项目。

我能想到的唯一机制是为每个从输入队列弹出的队列生成一个单独的线程,并将其馈送到原始线程可以等待的主队列中

每次我想从一组队列中弹出时,都要生成N个新线程,然后将它们全部杀死,这似乎有点耗费资源。

Golang是否实现了一些更优雅的机制,我可以在自己的C++代码中实现这些机制?

我不一定说Go的select实现很优雅,但我认为它以自己的方式很漂亮,而且经过了相当优化。

  • 它通过一个非默认情况特殊处理select
  • 它改变了评估案例的顺序,以避免确定性饥饿
  • 它乐观地第一次通过案例,寻找一个已经满意的案例
  • 它使用许多只为运行时机制所知的内部机制,在每个通道的内部发送方/接收方队列中排队
    • 它使用类似轻量级goroutine引用的sudog(同一个goroutine可能有许多sudog),允许快速跳转到goroutine堆栈
    • 它使用调度器的gopark机制来阻止自己,这允许对信号进行有效的解封
    • 当发出信号并取消标记时,它会通过操作select goroutine的程序计数器立即进入触发的事例处理程序函数

在实施过程中没有一个总体的突破性想法,但你会非常感激如何仔细地修改每一步,使其快速、高效,并与渠道的概念很好地结合在一起。正因为如此,用另一种语言重新实现Go的select语句并不容易,除非您至少首先拥有chan构造。

你可以看看其他语言中的重新实现,在这些语言中,这个想法以不同程度的相似性和有效性进行了重新实现。如果我必须用另一种语言从头开始重新实现select,我可能会首先尝试一个共享信号量,如果它不起作用,则切换到一个更粗糙的、睡眠不足的随机检查策略。

Golang的select语句的灵感来自C select函数(请参阅GNU libc文档),该函数用于等待一组文件描述符上的I/O。如果您的队列使用套接字或管道进行通信,则可以使用它。