fs: improve fsPromises readFile performance#37608
Conversation
|
@nodejs/fs @jasnell |
benjamingr
left a comment
There was a problem hiding this comment.
I went all the way back to https://github.com/nodejs/node/pull/18297/files to see if there is a compelling reason that buffer size was chosen - looks like it was tried initially and not really iterated on - so this change looks fine :)
@benjamingr I believe that the number was changed in |
|
cc @BridgeAR |
| readFile, | ||
| writeFile, | ||
| truncate | ||
| truncate, |
There was a problem hiding this comment.
| truncate, | |
| truncate |
nit: Unrelated change
There was a problem hiding this comment.
Personally I'm in favour of not spending mental energy on stylistic changes that are not enforced as part of linting rules.
|
I've copy-pasted the |
Improve the fsPromises readFile performance by allocating only one buffer, when size is known, increase the size of the readbuffer chunks, and dont read more data if size bytes have been read refs: nodejs#37583
ea69fbc to
1bbc2bb
Compare
add a benchmark for fs.promises.readFile
1bbc2bb to
e31ccd9
Compare
| buffer = fullBuffer; | ||
| offset = totalRead; | ||
| length = MathMin(size - totalRead, kReadFileBufferLength); | ||
| } |
There was a problem hiding this comment.
Note that this is a behavioral change for files that are being appended to while they are being read. I think that should be okay, because ultimately there are no guarantees for the relative timing of the two operations, but it might be something to keep in mind.
There was a problem hiding this comment.
Yes, you're correct and I should've mentioned it in the PR but forgot. This is aligning the behaviour with the cb version, so I thought that it would be OK.
node/lib/internal/fs/read_file_context.js
Line 110 in 26288ff
| const buf = Buffer.alloc(isFirstChunk ? firstChunkSize : chunkSize); | ||
| const { bytesRead, buffer } = | ||
| await read(filehandle, buf, 0, buf.length, -1); | ||
| endOfFile = bytesRead === 0; |
There was a problem hiding this comment.
nit: it looks like it should be enough to change this line to:
totalRead += bytesRead;
endOfFile = bytesRead === 0 || totalRead === size;in order to get the same performance improvement as in this PR (at least that's what I saw on my machine). Another useful optimization here is Buffer.allocUnsafeSlow. So, maybe it's worth considering keeping only these 4 lines of changes, but with the same result.
There was a problem hiding this comment.
I agree that some of the changes are not strictly necessary for the improvement, but another feature (IMO) of my changes it that now the logic is essentially the same as the sync readFile.
|
Landed in e2f5bb7...b9fd4eb |
Improve the fsPromises readFile performance by allocating only one buffer, when size is known. I also increased the size of the readbuffer chunks (which are now the same as in
read_file_context), and also removed the extra read ifsizebytes have been read.Most of the changes here are essentially shamelessly copied from
read_file_context, I've also removed a call to the innerreadand just calledbinding.readdirectly.I also had to fix a few abort-controller tests, as they were dependant on the extra read at the end of the file.
This improves the promises.readFile performance by 20% on my machine. However there is still a 15-20% difference between the cb version and this version on my machine, so I didn't mark this as resolving #37583
edit:
second commit contains fs.promises.readFile benchmark