为了账号安全,请及时绑定邮箱和手机立即绑定

如何决定并发操作的数量?

如何决定并发操作的数量?

Go
海绵宝宝撒 2022-05-10 14:11:59
我目前正在编写一个编码器,并且(显然)想让它变得更快。我有一个工作系统来进行编码(所以每个 goroutine 都在做同样的事情),但我正在努力寻找合适数量的 goroutine 来运行代码。我基本上想决定保持最大数量的 Goroutines CPU 忙。下面的想法掠过我的脑海:如果一个文件只有 <1 kB,那么在很多 goroutine 中运行代码是没有用的goroutines 的数量应该受可用的核心/线程的影响在 4x4 GHz CPU 上运行 16 个 goroutine 不会有问题,但在 4x1 GHz CPU 上呢?难以确定可靠的跨平台CPU 应该很忙,但不要忙到阻止其他程序响应(~70-ish %?)由于时钟速度和其他参数,很难事先决定现在我尝试根据这些因素来决定使用多少个 goroutine,但我不太确定如何跨平台并以可靠的方式这样做。已经尝试过:使用线性函数根据文件大小确定需要基于 CPU 的不同功能从 lscpu 解析 CPU 规格不跨平台需要另一个函数来根据频率确定这并不令人满意。
查看完整描述

1 回答

?
长风秋雁

TA贡献1757条经验 获得超7个赞

你在评论中提到


每个 goroutine 都在读取要编码的文件


但当然,文件——任何文件——已经以某种方式编码:也许是纯文本,或者是 UTF-8(字节流),也许是组装成“行”单元。或者它可能是一个图像流,例如一个 mpeg 文件,由一些帧组成。或者它可能是一个由记录组成的数据库。无论其输入形式是什么,它都包含某种基本单元,您可以将其提供给您的(重新)编码器。


那个单位,不管它是什么,都是一个合理的分工场所。(多么明智,取决于它是什么。请参阅下面的分块的想法。)


假设文件由独立的行组成:然后使用scanner.Scan来读取它们,并将每一行传递给一个接收行的通道。分拆 N,对于一些 N,阅读频道的读者,一次一行:


ch := make(chan string)

for i := 0; i < n; i++ {

    go readAndEncode(ch)

}


// later, or immediately:

for s := bufio.NewScanner(os.Stdin); s.Scan(); {

    ch <- s.Text()

}

close(ch)

如果有 100 行和 4 个阅读器,前四个ch <- s.Text()操作会快速进行,第五个操作会暂停,直到其中一个阅读器完成编码并返回读取通道。


如果单个行太小,也许您应该一次读取一个“块”(例如,1 MB)。如果块的末尾有部分行,请备份或阅读更多内容,直到您有整行。然后发送整个数据块。


因为通道复制数据,您可能希望发送对块的引用。1 这适用于任何更大的数据单元。(行往往很短,与首先使用通道的开销相比,复制它们的开销通常不是很大。如果你的行有 type string,那么,请参阅脚注。)


如果行或行块在这里不是正确的工作单元,请弄清楚什么是. 将 goroutine 想象为每个人都有一份工作要做的人(或忙碌的小地鼠) 。他们可以依靠其他人——另一个人或地鼠——来做一份较小的工作,不管那是什么;并且有十个人,或称地鼠,处理子任务允许主管管理它们。如果你需要做 N 次相同的工作,并且 N 不是无界的,你可以分拆 N 个 goroutine。如果 N可能是无界的,则分拆一个固定的数字(可能基于#cpus)并通过通道为它们提供工作。


1正如 Burak Serdar 所指出的,一些副本可以自动删除:例如,字符串实际上是只读切片。切片类型包含三个部分:指向底层数据的指针(引用)、长度和容量。复制切片会复制这三个部分,但不会复制底层数据。字符串也是如此:字符串标题省略了容量,因此通过通道发送字符串仅复制两个标题词。因此,许多明显且易于编码的数据分块方式已经非常有效。


查看完整回答
反对 回复 2022-05-10
  • 1 回答
  • 0 关注
  • 140 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号