`Writable.write(buf, sourceOffset, sourceLength)`
I want to add a Writable.write(sourceBuf, sourceOffset, sourceLength) API to Writable to get a bit of extra performance in the following case:
writable.write(buf.subarray(offset, length))
The subarray call (particularly regarding allocating Buffer) can be quite slow and avoided in this API. Hence I would like to be able to do something like:
writable.write(buf, offset, length)
I'm not sure how the API should look, though, or whether adding another signature to write would break anyone.
Internally stream implementation would need to explicitly support this by implementing something like _writeSlice and _writevSlice
@nodejs/streams @mcollina
I think the complexity budget is already over what we could afford in those methods, and I'm afraid adding this will slow everything down or make it even worse.
Why don't you explore doing this in OSS instead?
OSS?
Sorry, as a separate Open Source module.
I think this would need support in node core to be meaningful. The conversion into buffer happens in native code for many APIs.
I'm not convinced that allocating an object is the biggest cost here. It adds some overhead, but is it the biggest source of overhead to tackle? I'm afraid it would cost us massive refactors with little gains, but I'd be happy to be proven wrong.
import { bench, run } from 'mitata'
import { Writable } from 'node:stream'
const w = new Writable({
write (chunk, encoding, callback) {
callback()
}
})
const buf = Buffer.allocUnsafe(1024)
bench('writable w/ subarray', () => {
w.write(buf.subarray(0, 1023))
})
bench('writable w/o subarray', () => {
w.write(buf)
})
await run()
benchmark avg (min โฆ max) p75 p99 (min โฆ top 1%)
------------------------------------------- -------------------------------
writable w/ subarray 58.64 ns/iter 50.93 ns โ
(43.96 ns โฆ 2.15 ยตs) 183.88 ns โโโโโโโโโโโโโโโโโโโโโ
writable w/o subarray 29.68 ns/iter 21.47 ns โ
(19.82 ns โฆ 3.63 ยตs) 132.98 ns โโโโโโโโโโโโโโโโโโโโโ
Buffer object allocation is comically slow. Relatively speaking. Though I'm not sure 20ns is much in context of a real application.
Writing 1G of data it adds an overhead of 1e12 / 16e3 * 20 / 10e9 = 0,125s
Assuming a bandwidth of 1GB/s w/o subarray, that means that we would get 0,88GB/s w/ subarray... so it's not negligable
That's very odd, I didn't expect .subarray() to be so slow. It's not doing any copying or anything similar... therefore our FastBuffer does not seem that fast.
I can see why you'd want to do this, but it's a humungous change in the internals of streams, C++ streams, etc, and the majority of the ecosystem is not going to benefit from it, as it's a minor use case.
Maybe it could be investigated if .subarray() or Uint8Array initialization could be made faster.
Maybe it could be investigated if .subarray() or Uint8Array initialization could be made faster.
I have looked into it and it's in V8. Nothing we can do as far I can tell.
I'm not sure this is solvable then, unless there is a significant sponsor for redoing quite a large portion of the internal streams API. On top, it would not benefit the "base" case, making it even harder to "sell".
I will have a go at it if I ever have time.
There has been no activity on this feature request for 5 months. To help maintain relevant open issues, please add the https://github.com/nodejs/node/labels/never-stale label or close this issue if it should be closed. If not, the issue will be automatically closed 6 months after the last non-automated comment. For more information on how the project manages feature requests, please consult the feature request management document.
There has been no activity on this feature request and it is being closed. If you feel closing this issue is not the right thing to do, please leave a comment.
For more information on how the project manages feature requests, please consult the feature request management document.