Golang:通过缓冲通道通信时如何判断生产者或消费者是否较慢?

Tho*_*yen 6 concurrency channel producer-consumer go

我在 Golang 中有一个应用程序,其中有一个管道设置,其中每个组件执行一些工作,然后通过缓冲通道将其结果传递给另一个组件,然后该组件对其输入执行一些工作,然后将其结果传递给另一个组件通过另一个缓冲通道,等等。例如:

C1 -> C2 -> C3 -> ...

其中 C1、C2、C3 是管道中的组件,每个“->”是一个缓冲通道。

在 Golang 中,缓冲通道很棒,因为它迫使快速生产者放慢速度以匹配其下游消费者(或快速消费者放慢速度以匹配其上游生产者)。就像装配线一样,我的管道的移动速度与管道中最慢的组件一样快。

问题是我想找出管道中哪个组件是最慢的,这样我就可以专注于改进该组件,以使整个管道更快。

Golang 强制快速生产者或快速消费者放慢速度的方法是,当生产者尝试发送到已满的缓冲通道或消费者尝试从空通道进行消费时,阻止生产者。像这样:

outputChan <- result  // producer would block here when sending to full channel

input := <- inputChan // consumer would block here when consuming from empty channel
Run Code Online (Sandbox Code Playgroud)

这使得很难判断哪一个(生产者或消费者)阻塞最多,因此很难判断管道中最慢的组件。因为我不知道它阻塞了多长时间。阻塞时间最多的组件是最快的组件,而阻塞时间最少(或根本不阻塞)的组件是最慢的组件。

我可以在读取或写入通道之前添加这样的代码来判断它是否会阻塞:

// for producer
if len(outputChan) == cap(outputChan) {
    producerBlockingCount++
}
outputChan <- result

// for consumer
if len(inputChan) == 0 {
    consumerBlockingCount++
}
input := <-inputChan
Run Code Online (Sandbox Code Playgroud)

但是,这只能告诉我它被阻止的次数,而不是它被阻止的总时间。更不用说 TOCTOU 问题了,其中检查是针对单个时间点的,其中状态可能在检查后立即发生变化,从而导致检查不正确/误导。

任何去过赌场的人都知道,重要的不是你赢或输的次数,而是你赢或输的总金额。我可以输掉 10 手,每手 10 美元(总共损失 100 美元),然后赢得一手 150 美元,我仍然会领先。

同样,生产者或消费者被阻止的次数也没有意义。生产者或消费者被阻塞的总时间是决定它是否是最慢组件的决定因素。

但我无论如何也想不出确定在缓冲通道读取/写入时被阻止的总量。或者我的 google-fu 不够好。有人有什么好主意吗?

J_H*_*J_H 3

我想到了几种解决方案。

1.秒表

最不具有侵入性且最明显的方法是只记下每次读取或写入之前和之后的时间。记录、求和、报告总 I/O 延迟。同样报告经过的处理时间。

2. 基准测试

做一个综合工作台,让每个阶段对一百万个相同的输入进行操作,产生一百万个相同的输出。

或者进行“系统测试”,窃听流经生产的消息,将它们写入日志文件,并将相关日志消息重播到每个不同的管道阶段,测量经过的时间。由于重播,不会有 I/O 限制。

3. 发布/订阅

重新架构以使用更高开销的通信基础设施,例如 Kafka / 0mq / RabbitMQ。改变参与stage-1处理、stage-2等的节点数量。这个想法是压倒当前正在研究的阶段,没有空闲周期,以测量其饱和时的事务/秒吞吐量。

或者,只需将每个阶段分配到其自己的节点,并在正常系统行为期间测量 {user, sys,idle} 时间。