Quantcast
Channel: Node.jsタグが付けられた新着記事 - Qiita
Viewing all articles
Browse latest Browse all 9134

ES2022のArray.prototype.atは今の所遅い (2021/10/16時点)

$
0
0
Array.prototype.atは何ができるの Pythonのように, 負数を指定すると配列の後ろから取得できます. 特に最後尾の数個や, 文字列での末尾からの指定など, 待ち望まれていた機能です. (String.prototype.atもあります) const arr = [1, 2, 3] console.log(arr.at(-1)); // 3 速度 普通の添字で指定と速度を比べてみます. バージョンは > node -v v16.9.0 ソース const arr = [...Array(1000*1000)].map((_, i) => i); // for内の余分な計算は取っ払いたいので先に const len = arr.length; const len2 = len - 1; const nlen = -len; // [] 昇順 { const startTime = (new Date()).getTime(); for (let n = 0; n < 100; ++n) { for (let i = 0; i < len; ++i) { arr[i]; } } const endTime = (new Date()).getTime(); console.log(`インデックス昇順: ${endTime - startTime}ms`); } // [] 降順 { const startTime = (new Date()).getTime(); for (let n = 0; n < 100; ++n) { for (let i = len2; i >= 0; --i) { arr[i]; } } const endTime = (new Date()).getTime(); console.log(`インデックス降順 ${endTime - startTime}ms`); } // at 昇順 { const startTime = (new Date()).getTime(); for (let n = 0; n < 100; ++n) { for (let i = 0; i < len; ++i) { arr.at(i); } } const endTime = (new Date()).getTime(); console.log(`at昇順 ${endTime - startTime}ms`); } // at 降順 { const startTime = (new Date()).getTime(); for (let n = 0; n < 100; ++n) { for (let i = -1; i >= nlen; --i) { arr.at(i); } } const endTime = (new Date()).getTime(); console.log(`at降順 ${endTime - startTime}ms`); } 結果 インデックス昇順: 47ms インデックス降順 82ms at昇順 4189ms at降順 4462ms びっくりするほど遅いです. Chromeでも大体同じ傾向だったため, Nodejsの実装が特別悪いというわけでもなさそうです. polyfillのほうが大幅に速い? からコードを持ってきて, 簡易的に試してみます. Array.prototype.myat = function (n) { // ToInteger() abstract op n = Math.trunc(n) || 0; // Allow negative indexing from the end if (n < 0) n += this.length; // OOB access is guaranteed to return undefined if (n < 0 || n >= this.length) return undefined; // Otherwise, this is just normal property access return this[n]; } // myat 昇順 { const startTime = (new Date()).getTime(); for (let n = 0; n < 100; ++n) { for (let i = 0; i < len; ++i) { arr.myat(i); } } const endTime = (new Date()).getTime(); console.log(`myat昇順 ${endTime - startTime}ms`); } // myat 降順 { const startTime = (new Date()).getTime(); for (let n = 0; n < 100; ++n) { for (let i = -1; i >= mlen; --i) { arr.myat(i); } } const endTime = (new Date()).getTime(); console.log(`myat降順 ${endTime - startTime}ms`); } myat昇順 139ms myat降順 101ms 速いです. 一瞬バグではないかと思いましたが, 添字にNaNや文字列を入れたりしても挙動は合っていたので間違いではないようです. ループ数も100で合っています. 最初は遅い理由を関数のオーバーヘッドガーや単純に処理が多いからーなどと考えていましたが, そう簡単ではないようです. この先は実装を解明してもらえる方に… チラッ 現状組み込みのArray.prototype.atがびっくりするくらい遅いだけで, 本来は添字に近い性能が出るのではないかと思います. Webアプリ開発における普段使いでは大きな影響はないと思いますが, 将来的によく使う機能になると思うので今後の性能改善に期待です. 全体ソース const arr = [...Array(1000*1000)].map((_, i) => i); const len = arr.length; const len2 = len - 1; const nlen = -len; Array.prototype.myat = function (n) { // ToInteger() abstract op n = Math.trunc(n) || 0; // Allow negative indexing from the end if (n < 0) n += this.length; // OOB access is guaranteed to return undefined if (n < 0 || n >= this.length) return undefined; // Otherwise, this is just normal property access return this[n]; } // [] 昇順 { const startTime = (new Date()).getTime(); for (let n = 0; n < 100; ++n) { for (let i = 0; i < len; ++i) { arr[i]; } } const endTime = (new Date()).getTime(); console.log(`インデックス昇順: ${endTime - startTime}ms`); } // [] 降順 { const startTime = (new Date()).getTime(); for (let n = 0; n < 100; ++n) { for (let i = len2; i > 0; --i) { arr[i]; } } const endTime = (new Date()).getTime(); console.log(`インデックス降順 ${endTime - startTime}ms`); } // at 昇順 { const startTime = (new Date()).getTime(); for (let n = 0; n < 100; ++n) { for (let i = 0; i < len; ++i) { arr.at(i); } } const endTime = (new Date()).getTime(); console.log(`at昇順 ${endTime - startTime}ms`); } // at 降順 { const startTime = (new Date()).getTime(); for (let n = 0; n < 100; ++n) { for (let i = -1; i >= nlen; --i) { arr.at(i); } } const endTime = (new Date()).getTime(); console.log(`at降順 ${endTime - startTime}ms`); } // myat 昇順 { const startTime = (new Date()).getTime(); for (let n = 0; n < 100; ++n) { for (let i = 0; i < len; ++i) { arr.myat(i); } } const endTime = (new Date()).getTime(); console.log(`myat昇順 ${endTime - startTime}ms`); } // myat 降順 { const startTime = (new Date()).getTime(); for (let n = 0; n < 100; ++n) { for (let i = -1; i >= nlen; --i) { arr.myat(i); } } const endTime = (new Date()).getTime(); console.log(`myat降順 ${endTime - startTime}ms`); } ```  </div></details>

Viewing all articles
Browse latest Browse all 9134

Trending Articles