慢Buffer.concat

时间:2017-05-10 18:49:04

标签: node.js performance buffer

当我以64Kb的片段读取一个16MB的文件,并在每个片段上做Buffer.concat时,后者被证明非常慢,需要花费整整4个时间才能完成。

有没有更好的方法在Node.js中连接缓冲区?

使用的Node.js版本:7.10.0,在Windows 10下(均为64位)。

在研究以下问题时会询问此问题:https://github.com/brianc/node-postgres/issues/1286,会影响大量受众。

PostgreSQL驱动程序以64Kb的块读取大bytea列,然后将它们连接起来。我们发现调用Buffer.concat是导致此类示例中性能大幅下降的罪魁祸首。

2 个答案:

答案 0 :(得分:3)

不是每次都连接(每次都创建一个新的缓冲区),而是保留所有缓冲区的数组并在最后连接。

Buffer.concat()可以获取整个缓冲区列表。然后它在一次操作中完成。 https://nodejs.org/api/buffer.html#buffer_class_method_buffer_concat_list_totallength

答案 1 :(得分:1)

如果您从文件中读取文件并知道该文件的大小,则可以预分配最终缓冲区。然后,每次获取数据块时,只需将其写入到16Mb的大型缓冲区中即可。

// use the "unsafe" version to avoid clearing 16Mb for nothing
let buf = Buffer.allocUnsafe(file_size)

let pos = 0
file.on('data', (chunk) => {
    buf.fill(chunk, pos, pos + chunk.length)
    pos += chunk.length
})

if(pos != file_size) throw new Error('Ooops! something went wrong.')

与@Brad的代码示例的主要区别在于,您将(大约)使用16Mb +一个块的大小,而不是32Mb +一个块的大小。

此外,每个块都有一个头部,各种指针等,因此您不太可能使用33Mb甚至34Mb ...这会增加RAM。否则复制的RAM数量相同。话虽这么说,可能是Node在复制时开始读取下一个块,因此可以使其透明。在'end'事件中大块完成操作后,您将不得不等待contact()完成,而并行执行其他操作。


如果您正在接收HTTP POST并且正在读取它。请记住,您获得了一个Content-Length参数,因此在这种情况下也具有长度,并且可以在读取数据之前预先分配整个缓冲区。