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