缓冲通道的理想大小和工作器数量是多少?



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

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
}

实验后:结果有 2 个因素会影响此代码的性能

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

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

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

0 表示同步行为。

1 给出了异步行为:它在具有default大小写的select语句中很有用。

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

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

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

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

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

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

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

最新更新