如何将下面的线程模型从c++转换为go

How do I translate the following threading model from C++ to go?

本文关键字:c++ 转换 go 模型 线程      更新时间:2023-10-16

在我的c++项目中,我在磁盘上有一个大的GB二进制文件,我将它读入内存用于只读计算。

我目前的c++实现包括将整个块读入内存一次,然后生成线程从块中读取,以便进行各种计算(无互斥,运行迅速)。从技术上讲,每个线程一次实际上只需要文件的一小部分,因此在将来,我可能会更改此实现以使用mmap(),特别是当文件变得太大时。我已经注意到这个gommap库,所以我认为我应该继续讨论。

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

了goroutine吗?选择呢?

我相信这个答案会引起很多争议,但是下面是:

切换到Go不会减少运行时间,特别是如果你的代码已经没有互斥锁。Go不能保证有效地平衡程序,目前也不能充分利用可用的内核。生成的代码比c++慢。Go当前的优势在于清晰的抽象和并发性,而不是并行性。

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

如果有任何密集的例程间通信,或数据之间的依赖关系,你应该尝试使算法单线程。如果不更多地了解应用于数据的例程,这很难说,但听起来确实有可能您过早地取出线程,希望获得神奇的性能提升。

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

与往常一样,以下规则适用于优化。必须配置文件。您必须检查您对工作解决方案所做的更改是否正在改进。通常情况下,您会发现内存映射、线程和其他技巧对性能没有明显的影响。如果你从C或c++切换过来,这也是一场艰苦的战斗。

此外,您应该生成处理文件的每个部分的例程,并通过通道减少计算结果。请确保将GOMAXPROCS设置为合适的值。

此程序在多个例程中对文件中的所有字节求和(无需担心溢出)。

你需要重新实现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)
}