用布菲奥提高阅读性能。新扫描器

一个简单的程序,用于一个目的:

  1. 逐行读取脚本文件,创建字符串,同时忽略任何空白的新行或注释(包括 shebang)。如果需要,在行尾添加“;”。(我知道,我知道,反斜杠和 & 符号等)

我的问题是:

如何提高这个小程序的性能?在另一个答案中,我读到过利用而不是,但这似乎不可行,因为字符串是我想要的。scanner.Bytes()scanner.Text()

包含测试文件的示例代码:https://play.golang.org/p/gzSTLkP3BoB

这是一个简单的程序:

func main() {

    file, err := os.Open("./script.sh")

    if err != nil {

        log.Fatalln(err)

    }

    defer file.Close()


    var a strings.Builder

    scanner := bufio.NewScanner(file)


    for scanner.Scan() {

        lines := scanner.Text()


        switch {

        case lines == "" || lines[:1] == "#":

            continue

        case lines[len(lines)-1:] != ";":

            a.WriteString(lines + "; ")

        default:

            a.WriteString(lines + " ")

        }

    }


    fmt.Println(a.String())

}


烙印99
浏览 68回答 3
3回答

HUX布斯

我使用和来提高性能。当您处理小型shell脚本时,我认为一次读取所有文件不会对内存造成压力(我使用了)。我还只分配了一次,以便为减少分配提供足够的存储空间。strings.Builderioutil.ReadAllioutil.ReadAllstrings.Builder快速:更快的实施doSlow:实现速度较慢(您最初执行的操作)现在,让我们看一下基准测试结果:goos: darwingoarch: amd64pkg: testcpu: Intel(R) Core(TM) i5-1038NG7 CPU @ 2.00GHzBenchmarkDoFast-8         342602          3334 ns/op        1280 B/op          3 allocs/opBenchmarkDoSlow-8         258896          4408 ns/op        4624 B/op          8 allocs/opPASSok      test    2.477s我们可以看到,这不仅更快,而且只会减少分配。测量的指标越低越好。doFastpackage mainimport (    "bufio"    "bytes"    "fmt"    "io/ioutil"    "os"    "strings")func open(filename string) (*os.File, error) {    return os.Open(filename)}func main() {    fd, err := open("test.sh")    if err != nil {        panic(err)    }    defer fd.Close()    outputA, err := doFast(fd)    if err != nil {        panic(err)    }    fd.Seek(0, 0)    outputB, err := doSlow(fd)    if err != nil {        panic(err)    }    fmt.Println(outputA)    fmt.Println(outputB)}func doFast(fd *os.File) (string, error) {    b, err := ioutil.ReadAll(fd)    if err != nil {        return "", err    }    var res strings.Builder    res.Grow(len(b))    bLines := bytes.Split(b, []byte("\n"))    for i := range bLines {        switch {        case len(bLines[i]) == 0 || bLines[i][0] == '#':        case bLines[i][len(bLines[i])-1] != ';':            res.Write(bLines[i])            res.WriteString("; ")        default:            res.Write(bLines[i])            res.WriteByte(' ')        }    }    return res.String(), nil}func doSlow(fd *os.File) (string, error) {    var a strings.Builder    scanner := bufio.NewScanner(fd)    for scanner.Scan() {        lines := scanner.Text()        switch {        case lines == "" || lines[:1] == "#":            continue        case lines[len(lines)-1:] != ";":            a.WriteString(lines + "; ")        default:            a.WriteString(lines + " ")        }    }    return a.String(), nil}注意:我没有使用;是必需的吗?bufio.NewScanner

回首忆惘然

使用扫描仪是可行的。字节()。代码如下:func main() {    file, err := os.Open("./script.sh")    if err != nil {        log.Fatalln(err)    }    defer file.Close()    var a strings.Builder    scanner := bufio.NewScanner(file)    for scanner.Scan() {        lines := scanner.Bytes()        switch {        case len(lines) == 0 || lines[0] == '#':            continue        case lines[len(lines)-1] != ';':            a.Write(lines)            a.WriteString("; ")        default:            a.Write(lines)            a.WriteByte(' ')        }    }    fmt.Println(a.String())}此程序避免了扫描仪中的字符串分配。文本()。如果程序速度受到 I/O 的限制,则程序在实践中可能不会更快。在操场上奔跑。如果您的目标是将结果写入标准,则写入 bufio。编写器而不是字符串。建筑工人。此更改将替换字符串中的一个或多个分配。在布菲奥中具有单个分配的建筑商。作家。func main() {    file, err := os.Open("./script.sh")    if err != nil {        log.Fatalln(err)    }    defer file.Close()    a := bufio.NewWriter(os.Stdout)    defer a.Flush() // flush buffered data on return from main.    scanner := bufio.NewScanner(file)    for scanner.Scan() {        lines := scanner.Bytes()        switch {        case len(lines) == 0 || lines[0] == '#':            continue        case lines[len(lines)-1] != ';':            a.Write(lines)            a.WriteString("; ")        default:            a.Write(lines)            a.WriteByte(' ')        }    }}在操场上奔跑。额外改进:用于处理 a 之前和之后的空格lines := bytes.TrimSpace(scanner.Bytes())'#'';'

守候你守候我

您也可以通过缓冲输出来提高性能。func main() {  output := bufio.NewWriter(os.Stdout)  // instead of Printf, use  fmt.Fprintf(output, "%s\n", a)}
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go