【问题标题】:What's the ideal size of buffered channel and number of workers?缓冲通道的理想大小和工人数量是多少?
【发布时间】:2018-10-20 01:35:33
【问题描述】:

我正在尝试构建一个异步编解码器。我已经实现了一个作业调度程序,它可以访问缓冲的作业通道

var JobChannel chan Job = make(chan Job, 100000)

调度员将工作人员的数量作为输入并将工作分配给他们

func StartDispacher(numberOfWorkers int){
    // start workers
    wg := &sync.WaitGroup{}
    wg.Add(numberOfWorkers)
    for i := int(1); i <= numberOfWorkers; i++ {
        go func(i int) {
            defer wg.Done()
            for j := range JobChannel {
                doWork(i, j)
            }
        }(i)
    }
}

我的主要功能启动调度程序并不断为其分配工作(在本例中为 200000 个工作)

workDispatcher.StartDispacher(2*runtime.NumCPU())
for i := 0; i < 200000; i++ {
    j := workDispatcher.Job{
        BytePacket: d,
        JobType:    workDispatcher.DECODE_JOB,
    }
    workDispatcher.JobChannel <- j
}

经过实验:原来有两个因素会影响这段代码的性能

  • 缓冲通道的大小JobChannel
  • 那里的工人数量func StartDispacher(numberOfWorkers int)

是否有一种标准方法可以找到这些参数的最佳值,是否可以使这些值独立于运行代码的机器的物理设置?

【问题讨论】:

  • 最佳值完全取决于您的系统和要求。至于让它们“独立于物理设置”,你能解释一下你的意思吗?您当然可以使这些值可配置。
  • 我的意思是有某种公式可以实现为带有输入值的代码,从而为我提供最佳尺寸和工人数量
  • 在接近 99.999% 的情况下,“最佳”是您可以最快发布的任何内容。换句话说:为提高 1% 的吞吐量进行优化,可能会花费 2 周的额外工时。对于大多数应用程序来说,这是一个相当昂贵的改进。换一种说法:不要忘记优化时衡量性能所花费的时间。您的开发人员时间通常最好花在其他地方。

标签: asynchronous go dispatcher goroutine


【解决方案1】:

您始终需要进行测量以确定系统在负载下的性能。好消息是您只有 2 个变量,它们大多是独立的,因此很容易推理。

工作人员的数量决定了您的并发性,因此对处理进行基准测试以查看最佳并发性是多少。通常有许多并发进程,超过这些进程的回报会急剧下降。

通道的大小就像系统中的任何其他“缓冲区”一样。更大的缓冲区可以处理更大的输入峰值,但可能会导致更大的延迟和内存使用。

【讨论】:

  • 所以答案就是手动测试这两个变量的多个组合并坚持使用效果最好的那个?
  • @Mheni 但是对于一个特定的 CPU 来说最好的不一定是其他 CPU 的最好的,我什至没有考虑内存系统。
  • @Mheni,我会自动化测试,并记住结果仅对您测试的整个系统有效。
【解决方案2】:

在实践中,我发现三个缓冲区大小很重要:0、1 和“发送总数的上限”。

0 给出同步行为。

1 提供异步行为:它在带有 default 情况的 select 语句中很有用。

发送总数的上限保证了非阻塞行为:您可以在没有select 的情况下发送给它,而不会有 goroutine 泄漏的风险。

其他数字可能会提供稍微好一点的吞吐量,但在规模上它们仍然会竞争包含通道内部互斥体的缓存行,并且它们更有可能掩盖潜在的死锁和 goroutine 泄漏。

【讨论】:

  • 顺便说一句,我发现信号量通常比工作池更可取:它简化了清理工作,并允许您编写同步函数,降低 goroutine 泄漏的风险。有关示例,请参见 godoc.org/golang.org/x/sync/…
  • 您能澄清一下“1 给出异步行为”的含义吗?
  • 我的意思是当缓冲区大小为 1 时,发送方可以在缓冲区中放置一个项目并继续执行,而接收方可以稍后从缓冲区中删除一个项目并继续执行。通道的任何一侧都不一定需要阻止另一侧,尤其是在使用 selectdefault 的情况下。
【解决方案3】:

答案是否定的。最佳设置不仅取决于您在doWork 中运行的软件(该功能需要多少 CPU 密集型和 IO),还取决于您的硬件可以执行多少指令以及系统可以处理多少 IO。

这意味着如果您的系统执行涉及互联网访问的活动、您的 CPU 有多少物理内核等,它可能取决于您的系统安装或未安装 SSD 甚至您的带宽......

【讨论】:

  • 确实如此,但作为编解码器,我只依赖 CPU 和内存(不使用任何 IO 或网络)。考虑到这一点,是否可以为任何机器找到合适的通道大小 x
  • 那么您仍然可以访问内存、L1 和 L2 缓存以及物理内核的数量。
猜你喜欢
  • 2012-05-28
  • 1970-01-01
  • 2012-08-10
  • 2021-07-08
  • 2011-06-06
  • 1970-01-01
  • 2015-06-07
  • 2011-12-01
  • 1970-01-01
相关资源
最近更新 更多