Расширение массивов JavaScript в V8 и поддержка типа PACKED - PullRequest
0 голосов
/ 09 июля 2019

Я читал о упакованных массивах в движке V8 и хотел бы использовать их в некоторых критичных для производительности частях моей игры (например, в качестве контейнера для частиц).

Я хотел бы создать собственный подкласс Array, который всегда будет оставаться PACKED, но, похоже, невозможно расширить себя другим массивом.

class PackedArray extends Array {
    constructor() {
        super();
    }

    extend(values) {
        // `values` is another array.
        // This obviously won't work, is there another way?
        this = this.concat(values);
    }
}

Есть ли способ расширить экземпляр подклассового массива и сохранить тип PACKED в V8?

Я знаю, что могу выдвигать значения по одному или даже вызывать this.push(...values), но это медленнее, чем .concat() и не работает для больших массивов.

Ответы [ 2 ]

2 голосов
/ 09 июля 2019

V8 разработчик здесь. TL; DR: лучшее, что вы можете сделать с «упакованными элементами», это не беспокоиться о них. Разница почти никогда не измерима.

В некоторых микробенчмарках, где в оптимизированном коде для цикла с горячим ядром есть только несколько машинных инструкций, каждая отдельная инструкция имеет значение, и если проверка «дыры» для текущего элемента является одной из них (фактически два : cmp + je на x86), то отслеживание того, какие массивы не нужны, может повлиять на результат теста. Но в реальных приложениях, где вы выполняете нетривиальные операции над элементом массива, влияние двух машинных инструкций не измеримо. Любые искажения, с которыми вы сталкиваетесь с помощью своего пользовательского класса-оболочки, скорее всего, стоят дороже, чем незначительные накладные расходы, которые вы могли бы сэкономить.


Конкретный вопрос, который вы задаете, можно решить, выбрав композицию "has-a" вместо "is-a":

class PackedArray {
  extend(values) {
    this.#data = this.#data.concat(values);
  }
  get(i) { return this.#data[i]; }

  #data = [];
}

Что также решит проблему, связанную с тем, что в подклассе код все еще может использовать my_packed_array[10000] = "now you have holes" для обхода метода .extend(). Однако имейте в виду то, что я написал выше: результат проверки дырки крошечный , и любая из этих дополнительных упаковок, вероятно, стоит намного больше, чем экономит.

РЕДАКТИРОВАТЬ: то, что пишет @MathiasBynens, также является очень хорошим моментом: не оптимизируйте для V8, пусть V8 оптимизирует для вас! : -)

0 голосов
/ 09 июля 2019

Вы можете использовать this.splice() для изменения текущего массива.

extend(values) {
    this.splice(this.length, 0, ...values);
}
...