如何将以下线程模型从C ++转换为?

时间:2011-10-22 10:55:45

标签: c++ multithreading memory go

在我的C ++项目中,我在磁盘上有一个大的GB二进制文件,我将其读入内存以进行只读计算。

我当前的C ++实现涉及将整个块读取到内存中,然后生成线程以从块中读取,以便进行各种计算(无互斥并快速运行)。从技术上讲,每个线程实际上一次只需要文件的一小部分,所以将来我可能会改变这个实现来使用mmap(),特别是如果文件太大的话。我已经注意到了gommap lib,所以我认为我应该接受这个问题。

我应该采用什么方法将我当前的C ++线程模型(一大块只读内存)转换为去线程模型,以保持运行时效率?

够程?替代?

2 个答案:

答案 0 :(得分:3)

我确信这个答案会带来很多热,但是这里有:

切换到Go不会减少运行时间,特别是如果您的代码已经是互斥的话。 Go不保证goroutine的有效平衡,并且目前不能充分利用可用的核心。生成的代码比C ++慢。 Go目前的优势在于清晰的抽象和并发性,不是并行性。

如果您必须通过内存进行回溯,那么预先读取整个文件并不是特别有效。直到很久之后才会再次使用的文件部分将从缓存中删除,以后再重新加载。如果您的平台允许,您应该考虑内存映射,以便在需要时从磁盘加载页面。

如果存在任何强烈的例程间通信或数据之间的依赖关系,则应尝试使算法单线程化。如果不了解更多关于你正在应用于数据的例程,很难说,但是你有可能过早地提取线程,希望能够获得神奇的性能提升。

如果由于文件大小或其他平台限制而无法依赖内存映射,则应考虑使用pread调用,从而重用单个文件描述符,并仅根据需要进行读取。

与往常一样,以下规则适用于优化。您必须个人资料。您必须检查您从工作解决方案所做的更改是否正在改进。通常,您会发现内存映射,线程和其他恶作剧对性能没有任何明显影响。如果你不再使用C或C ++,这也是一场艰苦的战斗。

此外,您应该生成goroutine来处理文件的每个部分,并通过通道减少计算结果。请务必将GOMAXPROCS设置为适当的值。

答案 1 :(得分:1)

该程序将多个goroutine中文件中的所有字节相加(无需担心溢出)。

您需要为您的案例重新实现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)
}