【问题标题】:How are golang select statements implemented?golang select语句是如何实现的?
【发布时间】:2016-08-29 12:08:17
【问题描述】:

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

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

每次我想从一组队列中弹出时,生成 N 个新线程然后将它们全部杀死似乎是一种资源繁重。

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

【问题讨论】:

  • 我认为您不能仅使用标准工具在一个线程中等待多个条件变量。也许您可以反转问题,让队列主动推送到“主”队列中,它们现在通知阻塞线程。
  • Go 的 select 实现是here,也许它可以给你一些想法。

标签: c++ multithreading go


【解决方案1】:

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

  • 它使用单个非默认情况对 selects 进行特殊处理
  • 它改变了评估案例的顺序以避免确定性饥饿
  • 它在寻找已经满足的情况下进行乐观的第一次检查
  • 它在每个通道的内部发送者/接收者队列中使用许多内部队列,只有运行时机制知道
    • 它使用sudogs,类似于轻量级 goroutine 引用(同一个 goroutine 可以有多个 sudogs),允许快速跳转到 goroutine 堆栈中
    • 它使用调度程序的 gopark 机制来阻止自身,从而允许在信号上有效地解除驻留
    • 当发出信号并取消驻留时,它会立即通过操纵 select goroutine 的程序计数器进入触发的案例处理函数

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

您可以查看其他语言中可用的重新实现,其中的想法以不同程度的相似性和有效性重做。如果我必须用另一种语言从头开始重新实现select,我可能会首先尝试一个共享信号量,如果不起作用,则切换到更粗略的、稍微睡眠一下然后签到-随机顺序策略。

【讨论】:

    【解决方案2】:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-01-28
      • 1970-01-01
      • 1970-01-01
      • 2016-08-04
      • 2021-09-01
      • 1970-01-01
      相关资源
      最近更新 更多