Memory 使用io.Writer时避免golang内存分配过多

Memory 使用io.Writer时避免golang内存分配过多,memory,go,profiling,heap-memory,Memory,Go,Profiling,Heap Memory,我正在Go中开发一个名为的命令行工具,该工具将一组redis命令转换为 第一步是移植node.js版本,这几乎是字面意思。我使用ioutil.ReadFile(inputFileName)获取文件的字符串版本,然后返回一个编码字符串作为输出 当我在一个包含2000000个redis命令的文件上运行此命令时,大约需要8秒,而节点版本大约需要16秒。我猜它的速度只有原来的两倍是因为它首先将整个文件读入内存,所以我更改了编码函数以接受一对(raw io.Reader,enc io.Writer),如下

我正在Go中开发一个名为的命令行工具,该工具将一组redis命令转换为

第一步是移植node.js版本,这几乎是字面意思。我使用
ioutil.ReadFile(inputFileName)
获取文件的字符串版本,然后返回一个编码字符串作为输出

当我在一个包含2000000个redis命令的文件上运行此命令时,大约需要8秒,而节点版本大约需要16秒。我猜它的速度只有原来的两倍是因为它首先将整个文件读入内存,所以我更改了编码函数以接受一对
(raw io.Reader,enc io.Writer)
,如下所示:

func EncodeStream(raw io.Reader, enc io.Writer) {
    var args []string
    var length int

    scanner := bufio.NewScanner(raw)

    for scanner.Scan() {
            command := strings.TrimSpace(scanner.Text())
            args = parse(command)
            length = len(args)
            if length > 0 {
                    io.WriteString(enc, fmt.Sprintf("*%d\r\n", length))
                    for _, arg := range args {
                            io.WriteString(enc, fmt.Sprintf("$%d\r\n%s\r\n", len(arg), arg))
                    }
            }
    }
}
然而,这在200万行文件上花费了12秒,因此我使用github.com/pkg/profile查看了它是如何使用内存的,看起来内存分配的数量是巨大的:

# Alloc = 3162912
# TotalAlloc = 1248612816
# Mallocs = 46001048
# HeapAlloc = 3162912
我是否可以限制io.Writer使用固定大小的缓冲区并避免所有这些分配


更一般地说,如何避免这种方法中的过度分配

Writer没有缓冲区,它是一个接口。在您的代码中,为什么要缓冲缓冲区?谁说您所有的alloc都在
io.Writer
?您认为
command:=strings.TrimSpace(scanner.Text())
有什么作用?我认为它造成了大约200万个alloc。
fmt.Sprintf
也导致了很多alloc。没错,我问的问题不对,还有,好消息,我已经取消了字节缓冲。缓冲区,在最新的Master中,如果你想减少分配,避免字符串操纵是很有用的。尽可能多地使用和重用[]字节片。