当我以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
是导致此类示例中性能大幅下降的罪魁祸首。
答案 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
参数,因此在这种情况下也具有长度,并且可以在读取数据之前预先分配整个缓冲区。