在我的C++项目中,我在磁盘上有一个大的GB二进制文件,我将该文件读入内存进行只读计算。
,我目前的C++实现包括将整个块读入内存一次,然后生成线程从块读取,以便进行各种计算(没有互斥量,并且运行很快)。从技术上讲,每个线程一次只需要文件的一小部分,所以在将来,我可能会将这个实现更改为使用mmap(),特别是当文件变得太大时。我已经注意到了这个gommap库,所以我认为我应该继续前进。
我应该采取什么方法来将我当前的C++线程模型(一大块只读内存)转换成一个go线程模型,同时考虑到运行时的效率?
戈鲁蒂人?其他选择?
发布于 2011-10-22 11:16:44
我相信这个答案会引起很大的反响,但我要说:
切换到Go不会减少运行时间,特别是在代码已经没有互斥的情况下。Go并不能保证高效率的平衡,而且目前也无法充分利用可用的内核。生成的代码比C++慢。Go目前的优势在于抽象清晰、并发性、而不是并行性。
预先读取整个文件并不是特别有效,如果你不得不通过内存进行回溯。直到很长一段时间后才会从缓存中删除文件的一部分,然后再重新加载。如果您的平台允许的话,您应该考虑内存映射,以便按需要从磁盘加载页面。
如果有任何激烈的程序间通信,或数据之间的依赖,您应该尝试使算法单线程。如果不了解应用于数据的例程,就很难说出来了,但听起来确实有可能过早地拔出线程,希望得到神奇的性能提升。
如果由于文件大小或其他平台约束而无法依赖内存映射,则应考虑使用扩展调用,从而重用单个文件描述符,并且只根据需要读取。
与往常一样,以下规则适用于优化。您必须配置文件。您必须检查您从工作解决方案中所做的更改是否正在改进。通常,您会发现内存映射、线程和其他诡计对性能没有明显的影响。这也是一场艰难的战斗,如果你是从C或C++切换。
此外,您应该生成goroutines来处理文件的每个部分,并通过一个通道减少计算结果。确保将GOMAXPROCS设置为适当的值。
发布于 2011-10-22 19:17:49
这个程序将文件中的所有字节加在多个goroutines中(而不必担心溢出)。
您需要为您的情况重新实现processChunk和aggregateResults。您还可能希望更改结果通道的通道类型。根据您正在做的事情,您甚至可能不需要聚合结果。块大小和通道的缓冲区大小是您可以调整的其他旋钮。
package main
import (
"fmt"
"io/ioutil"
)
func main() {
data, err := ioutil.ReadFile("filename")
if err != nil {
// handle this error somehow
panic(err.String())
}
// Adjust this to control the size of chunks.
// I've chosen it arbitrarily.
const chunkSize = 0x10000
// This channel's unbuffered. Add a buffer for better performance.
results := make(chan int64)
chunks := 0
for len(data) > 0 {
size := chunkSize
if len(data) < chunkSize {
size = len(data)
}
go processChunk(data[:size], results)
data = data[size:]
chunks++
}
aggregateResults(results, chunks)
}
func processChunk(chunk []byte, results chan int64) {
sum := int64(0)
for _, b := range chunk {
sum += int64(b)
}
results <- sum
}
func aggregateResults(results chan int64, chunks int) {
sum := int64(0)
for chunks > 0 {
sum += <-results
chunks--
}
fmt.Println("The sum of all bytes is", sum)
}https://stackoverflow.com/questions/7858988
复制相似问题