-
Notifications
You must be signed in to change notification settings - Fork 29.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
stream: use instanceof when checking chunk type #19872
Conversation
Use the `instanceof` operator instead of `Stream._isUint8Array()` when checking if a chunk is a `Uint8Array` as this is faster.
i feel compelled to mention |
@devsnek |
@lpinca why not then change util.types.isUint8Array to use instanceof |
Yes it makes sense. |
It seems that // start: copied from /lib/internal/util/types.js
const ReflectApply = Reflect.apply;
function uncurryThis(func) {
return (thisArg, ...args) => ReflectApply(func, thisArg, args);
}
const TypedArrayPrototype = Object.getPrototypeOf(Uint8Array.prototype);
const TypedArrayProto_toStringTag =
uncurryThis(
Object.getOwnPropertyDescriptor(TypedArrayPrototype,
Symbol.toStringTag).get);
function isUint8Array(value) {
return TypedArrayProto_toStringTag(value) === 'Uint8Array';
}
// end: copied from /lib/internal/util/types.js
let a={__proto__:Uint8Array.prototype}
console.log(
a instanceof Uint8Array, // true
isUint8Array(a) // false
) Also see (Uint8Array might also in the same case): https://stackoverflow.com/a/22289982 |
@anliting good point. That's a good reason to not change |
This might potentially be breaking because If you are looking for a faster alternative, did you try
That defeats the purpose of having these functions – the |
It has the same performance of const assert = require('assert');
class Foo {
get [Symbol.toStringTag]() {
return 'Uint8Array';
}
}
const foo = new Foo();
assert(foo[Symbol.toStringTag] === 'Uint8Array'); |
In general: I am a fan of having strict type checks. In this specific case, I believe it will not make a difference besides the performance gain, so I am +1.
The first check does not seem to be breaking, because it will just allow weird chunks to be accepted instead of throwing an error. The second entry seems different though and it could be counted as breaking. But why would someone want to try to pass in a manipulated chunk? It would only be bad for the user in that case, so I do not see an issue there either. |
The compatibility issue at play is that this will no longer accept Uint8Array objects from other contexts. I am not convinced this is a good idea. It’s not that this new check is “not as strict,” but rather “not as correct.” I would also be very much surprised if the result from this benchmark affects any real-world applications of Node.js. |
I will also note that V8 has been willing to do more optimizations on |
@TimothyGu thanks a lot for bringing up the context. I did not think about that anymore. |
The referenced issue is marked as fixed. So master should already reflect that performance boost with the |
Yes, it is no longer 2/3x slower but still not as fast as Also please take a look at #19559 which is the reason why I would like to make |
Yes, it’s a general issue with Also, by the way: We did move away from
It can be fooled, but if it is, I think we can assume that it’s intentional – and the approach does work in a multi-context way. Benchmark CI: https://ci.nodejs.org/view/Node.js%20benchmark/job/benchmark-node-micro-benchmarks/153/ |
@addaleax yes my point was that we still have the context issue in other places in particular with Fooling |
Not really, I guess.
I don’t know, tbh. Fwiw, here’s the PR that originally moved away from |
I remember, |
With Turbofan |
@lpinca How did you benchmark this? The benchmark CI shows no significant results for streams (positive or negative), which is kind of surprising to me. |
@addaleax benchmark source is in PR description. You started it on master where the impact is low. |
@lpinca I see – I’m not sure then what to think. I would probably consider this a breaking change, but it seems like the places where we’d actually want it are v8.x and v9.x? |
Yes, if it can't be backported it doesn't make sense. it's a ~6% improvement on read and ~6% on write, not bad for duplex streams, multiply that for thousands of streams and the gain is not insignificant imho. There are no explicit -1 yet but it seems people are inclined toward that. If anyone makes it explicit I'll close this. |
I have no strong opinion about this and would like to defer this to @addaleax |
No approvals or disapprovals, this is going nowhere, closing. |
Use the
instanceof
operator instead ofStream._isUint8Array()
whenchecking if a chunk is a
Uint8Array
as this is faster.Node.js 9.11.1:
Node.js master:
Checklist
make -j4 test
(UNIX), orvcbuild test
(Windows) passes