Heim  >  Artikel  >  Backend-Entwicklung  >  Was ist der schnellste Weg, eine Datei in go neu zu schreiben?

Was ist der schnellste Weg, eine Datei in go neu zu schreiben?

王林
王林nach vorne
2024-02-06 09:33:071216Durchsuche

用 go 重写文件最快的方法是什么

问题内容

我有一个大文件(无法完全放入内存),其中包含各种大小的字符串。我想将这些字符串重写到另一个文件中,但每个字符串都大写。在 go 中实现这一目标的最快方法是什么?

这是我能想到的最有效的方法。关于如何使其更快的任何想法?

package main

import (
    "bufio"
    "log"
    "os"
    "strings"
)

func main() {
    inputFile, err := os.Open("input.txt")
    if err != nil {
        log.Fatal(err)
    }
    defer inputFile.Close()

    outputFile, err := os.Create("output.txt")
    if err != nil {
        log.Fatal(err)
    }
    defer outputFile.Close()

    scanner := bufio.NewScanner(inputFile)
    writer := bufio.NewWriter(outputFile)

    for scanner.Scan() {
        line := scanner.Text()
        capitalized := strings.ToUpper(line)
        _, err := writer.WriteString(capitalized + "\\n")
        if err != nil {
            log.Fatal(err)
        }
    }

    err = writer.Flush()
    if err != nil {
        log.Fatal(err)
    }
}

正确答案


一个起点是运行 go 测试包 基准测试。

对于基准数据,我使用 275,502 个单词(大部分为小写)、3,077,701 字节的 linux 字典文件:/usr/share/dict/brazilian。鉴于您对文件的模糊描述,这是我能做的最好的事情。为了避免基准磁盘 i/o,我对 io.reader 使用 bytes.reader,对 io.writer 使用 ioutil.discard。

代码的结果:

$ go test upper_so_test.go -run=! -benchmem -bench=.
benchmarkso-12   48  22765120 ns/op  8143216 b/op  550993 allocs/op

blunderific 代码的结果:

benchmarkb-12    94  13061407 ns/op  3782866 b/op  275505 allocs/op

作为概念验证 (poc),我使用字典文件编写了使用最少 cpu 和内存的代码。到目前为止,我的 poc 代码的结果:

benchmarktu-12  182   6457334 ns/op     8240 b/op       3 allocs/op

将我的 poc 代码作为程序运行,使用 ssd 文件存储来读取和写入字典文件,需要几毫秒的时间:

$ time ./upper
real    0m0.031s
user    0m0.014s
sys     0m0.009s

即使没有文件的一小部分样本,也无法提出性能改进的具体建议。然而,使用字典文件,我的 poc 基准测试结果与您的基准测试结果(6,457,334 ns/op vs. 22,765,120、8,240 b/op vs. 8,143,216、3 allocs/op vs. 550,993)确实表明您对 cpu 的过度使用内存会损害性能。

upper_so_test.go:

package main

import (
    "bufio"
    "bytes"
    "io"
    "io/ioutil"
    "os"
    "strings"
    "testing"
)

func SOToUpper(r io.Reader, w io.Writer) error {
    scanner := bufio.NewScanner(r)
    writer := bufio.NewWriter(w)
    for scanner.Scan() {
        line := scanner.Text()
        capitalized := strings.ToUpper(line)
        _, err := writer.WriteString(capitalized + "\n")
        if err != nil {
            return err
        }
    }
    err := writer.Flush()
    if err != nil {
        return err
    }
    return nil
}

var benchData = func () []byte {
    data, err := os.ReadFile(`/usr/share/dict/brazilian`)
    if err != nil {
        panic(err)
    }
    return data
}()

func BenchmarkSO(b *testing.B) {
    for i := 0; i < b.N; i++ {
        r := bytes.NewReader(benchData)
        w := ioutil.Discard
        err := SOToUpper(r, w)
        if err != nil {
            b.Error(err)
        }
    }
}

Das obige ist der detaillierte Inhalt vonWas ist der schnellste Weg, eine Datei in go neu zu schreiben?. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Dieser Artikel ist reproduziert unter:stackoverflow.com. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen