慢 Buffer.concat
Slow Buffer.concat
当我以 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
是此类示例中性能大幅下降的罪魁祸首。
与其每次都连接(每次都创建一个新缓冲区),不如保留所有缓冲区的数组并在最后连接。
Buffer.concat()
可以获取整个缓冲区列表。然后它在一次操作中完成。 https://nodejs.org/api/buffer.html#buffer_class_method_buffer_concat_list_totallength
如果您从文件中读取并且知道该文件的大小,那么您可以pre-allocate 最终缓冲区。然后每次你得到一大块数据,你可以简单地将它写入那个大的 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 + 一个块的大小。
此外,每个块都有一个 header、各种指针等,因此您不太可能使用 33Mb 甚至 34Mb...那是更多的 RAM。复制的 RAM 量在其他方面是相同的。话虽如此,Node 可能会在您复制时开始读取下一个块,因此它可以使其透明。当在 'end'
事件中以一大块完成时,您将不得不等待 contact()
完成,同时不并行执行任何其他操作。
以防您收到 HTTP POST
并正在阅读。请记住,您获得了一个 Content-Length
参数,因此在这种情况下您也有长度,并且可以 pre-allocate 在读取数据之前整个缓冲区。
当我以 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
是此类示例中性能大幅下降的罪魁祸首。
与其每次都连接(每次都创建一个新缓冲区),不如保留所有缓冲区的数组并在最后连接。
Buffer.concat()
可以获取整个缓冲区列表。然后它在一次操作中完成。 https://nodejs.org/api/buffer.html#buffer_class_method_buffer_concat_list_totallength
如果您从文件中读取并且知道该文件的大小,那么您可以pre-allocate 最终缓冲区。然后每次你得到一大块数据,你可以简单地将它写入那个大的 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 + 一个块的大小。
此外,每个块都有一个 header、各种指针等,因此您不太可能使用 33Mb 甚至 34Mb...那是更多的 RAM。复制的 RAM 量在其他方面是相同的。话虽如此,Node 可能会在您复制时开始读取下一个块,因此它可以使其透明。当在 'end'
事件中以一大块完成时,您将不得不等待 contact()
完成,同时不并行执行任何其他操作。
以防您收到 HTTP POST
并正在阅读。请记住,您获得了一个 Content-Length
参数,因此在这种情况下您也有长度,并且可以 pre-allocate 在读取数据之前整个缓冲区。