mirror of
https://github.com/denoland/deno.git
synced 2024-12-22 15:24:46 -05:00
perf(ext/streams): optimize async iterator (#20541)
This PR optimizes `ReadableStream` async iterator ### Benchmarks ```js Deno.bench("Stream - iterator", async () => { const stream = new ReadableStream({ start(controller) { controller.enqueue(new Uint8Array([97])); controller.enqueue(new Uint8Array([97])); controller.close(); }, }); for await (const chunk of stream) {} }); ``` **main** `2 chunks` ``` cpu: 13th Gen Intel(R) Core(TM) i9-13900H runtime: deno 1.36.4 (x86_64-unknown-linux-gnu) benchmark time (avg) iter/s (min … max) p75 p99 p995 ----------------------------------------------------------------------- ----------------------------- Stream - iterator 12.45 µs/iter 80,295.5 (10.5 µs … 281.12 µs) 12.13 µs 26.71 µs 33.63 µs ``` `20 chunks` ``` benchmark time (avg) iter/s (min … max) p75 p99 p995 ----------------------------------------------------------------------- ----------------------------- Stream - iterator 32.99 µs/iter 30,312.2 (28.13 µs … 1.21 ms) 31.8 µs 81.82 µs 179.93 µs ``` --- **this PR** `2 chunks` ``` cpu: 13th Gen Intel(R) Core(TM) i9-13900H runtime: deno 1.36.4 (x86_64-unknown-linux-gnu) benchmark time (avg) iter/s (min … max) p75 p99 p995 ----------------------------------------------------------------------- ----------------------------- Stream - iterator 9.37 µs/iter 106,700.8 (8.35 µs … 730.71 µs) 9.15 µs 13.12 µs 18.17 µs ``` `20 chunks` ``` benchmark time (avg) iter/s (min … max) p75 p99 p995 ----------------------------------------------------------------------- ----------------------------- Stream - iterator 16.59 µs/iter 60,270.0 (12.08 µs … 1.37 ms) 15.06 µs 83.03 µs 123.52 µs ```
This commit is contained in:
parent
fa18878f54
commit
4960b6659c
1 changed files with 8 additions and 30 deletions
|
@ -53,10 +53,8 @@ const {
|
||||||
NumberIsInteger,
|
NumberIsInteger,
|
||||||
NumberIsNaN,
|
NumberIsNaN,
|
||||||
ObjectCreate,
|
ObjectCreate,
|
||||||
ObjectDefineProperties,
|
|
||||||
ObjectDefineProperty,
|
ObjectDefineProperty,
|
||||||
ObjectGetPrototypeOf,
|
ObjectGetPrototypeOf,
|
||||||
ObjectPrototype,
|
|
||||||
ObjectPrototypeIsPrototypeOf,
|
ObjectPrototypeIsPrototypeOf,
|
||||||
ObjectSetPrototypeOf,
|
ObjectSetPrototypeOf,
|
||||||
Promise,
|
Promise,
|
||||||
|
@ -4651,26 +4649,6 @@ function writableStreamUpdateBackpressure(stream, backpressure) {
|
||||||
stream[_backpressure] = backpressure;
|
stream[_backpressure] = backpressure;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @template T
|
|
||||||
* @param {T} value
|
|
||||||
* @param {boolean} done
|
|
||||||
* @returns {IteratorResult<T>}
|
|
||||||
*/
|
|
||||||
function createIteratorResult(value, done) {
|
|
||||||
const result = ObjectCreate(ObjectPrototype);
|
|
||||||
ObjectDefineProperties(result, {
|
|
||||||
value: { value, writable: true, enumerable: true, configurable: true },
|
|
||||||
done: {
|
|
||||||
value: done,
|
|
||||||
writable: true,
|
|
||||||
enumerable: true,
|
|
||||||
configurable: true,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @type {AsyncIterator<unknown, unknown>} */
|
/** @type {AsyncIterator<unknown, unknown>} */
|
||||||
const asyncIteratorPrototype = ObjectGetPrototypeOf(AsyncGeneratorPrototype);
|
const asyncIteratorPrototype = ObjectGetPrototypeOf(AsyncGeneratorPrototype);
|
||||||
|
|
||||||
|
@ -4685,7 +4663,7 @@ const readableStreamAsyncIteratorPrototype = ObjectSetPrototypeOf({
|
||||||
const reader = this[_reader];
|
const reader = this[_reader];
|
||||||
function nextSteps() {
|
function nextSteps() {
|
||||||
if (reader[_iteratorFinished]) {
|
if (reader[_iteratorFinished]) {
|
||||||
return PromiseResolve(createIteratorResult(undefined, true));
|
return PromiseResolve({ value: undefined, done: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
if (reader[_stream] === undefined) {
|
if (reader[_stream] === undefined) {
|
||||||
|
@ -4701,11 +4679,11 @@ const readableStreamAsyncIteratorPrototype = ObjectSetPrototypeOf({
|
||||||
/** @type {ReadRequest} */
|
/** @type {ReadRequest} */
|
||||||
const readRequest = {
|
const readRequest = {
|
||||||
chunkSteps(chunk) {
|
chunkSteps(chunk) {
|
||||||
promise.resolve(createIteratorResult(chunk, false));
|
promise.resolve({ value: chunk, done: false });
|
||||||
},
|
},
|
||||||
closeSteps() {
|
closeSteps() {
|
||||||
readableStreamDefaultReaderRelease(reader);
|
readableStreamDefaultReaderRelease(reader);
|
||||||
promise.resolve(createIteratorResult(undefined, true));
|
promise.resolve({ value: undefined, done: true });
|
||||||
},
|
},
|
||||||
errorSteps(e) {
|
errorSteps(e) {
|
||||||
readableStreamDefaultReaderRelease(reader);
|
readableStreamDefaultReaderRelease(reader);
|
||||||
|
@ -4718,7 +4696,7 @@ const readableStreamAsyncIteratorPrototype = ObjectSetPrototypeOf({
|
||||||
reader[_iteratorNext] = null;
|
reader[_iteratorNext] = null;
|
||||||
if (result.done === true) {
|
if (result.done === true) {
|
||||||
reader[_iteratorFinished] = true;
|
reader[_iteratorFinished] = true;
|
||||||
return createIteratorResult(undefined, true);
|
return { value: undefined, done: true };
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}, (reason) => {
|
}, (reason) => {
|
||||||
|
@ -4743,12 +4721,12 @@ const readableStreamAsyncIteratorPrototype = ObjectSetPrototypeOf({
|
||||||
const reader = this[_reader];
|
const reader = this[_reader];
|
||||||
const returnSteps = () => {
|
const returnSteps = () => {
|
||||||
if (reader[_iteratorFinished]) {
|
if (reader[_iteratorFinished]) {
|
||||||
return PromiseResolve(createIteratorResult(arg, true));
|
return PromiseResolve({ value: arg, done: true });
|
||||||
}
|
}
|
||||||
reader[_iteratorFinished] = true;
|
reader[_iteratorFinished] = true;
|
||||||
|
|
||||||
if (reader[_stream] === undefined) {
|
if (reader[_stream] === undefined) {
|
||||||
return PromiseResolve(createIteratorResult(undefined, true));
|
return PromiseResolve({ value: undefined, done: true });
|
||||||
}
|
}
|
||||||
assert(reader[_readRequests].length === 0);
|
assert(reader[_readRequests].length === 0);
|
||||||
if (this[_preventCancel] === false) {
|
if (this[_preventCancel] === false) {
|
||||||
|
@ -4757,7 +4735,7 @@ const readableStreamAsyncIteratorPrototype = ObjectSetPrototypeOf({
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
readableStreamDefaultReaderRelease(reader);
|
readableStreamDefaultReaderRelease(reader);
|
||||||
return PromiseResolve(createIteratorResult(undefined, true));
|
return PromiseResolve({ value: undefined, done: true });
|
||||||
};
|
};
|
||||||
|
|
||||||
const returnPromise = reader[_iteratorNext]
|
const returnPromise = reader[_iteratorNext]
|
||||||
|
@ -4765,7 +4743,7 @@ const readableStreamAsyncIteratorPrototype = ObjectSetPrototypeOf({
|
||||||
: returnSteps();
|
: returnSteps();
|
||||||
return PromisePrototypeThen(
|
return PromisePrototypeThen(
|
||||||
returnPromise,
|
returnPromise,
|
||||||
() => createIteratorResult(arg, true),
|
() => ({ value: arg, done: true }),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
}, asyncIteratorPrototype);
|
}, asyncIteratorPrototype);
|
||||||
|
|
Loading…
Reference in a new issue