Спасибо всем, кто участвовал в нашем конкурсе по программированию! Мы подвели его итоги и наградили победителей.

Задача состояла в том, чтобы улучшить реализацию двусвязного списка из исходников Node.js. Этот код быстрый и эффективный, но он был написан под конкретное применение — хранение списков неактивных таймеров. Поэтому прямо в хранимые объекты там добавляются поля idleNext и idlePrev. Перед участниками конкурса стояла задача сделать код универсальным (так, чтобы один элемент мог принадлежать одновременно нескольким независимым спискам) без потери производительности.

Очевидное решение состоит в том, чтобы добавить промежуточные объекты — звенья списка — содержащие поля next, prev и value. Но у этого подхода есть серьёзный недостаток: если у нас есть только ссылка на хранимый объект, и его надо удалить из списка, то придётся перебирать всю цепочку. Налицо потеря производительности.

Более высоко мы оценили те решения, где вместо полей idleNext и idlePrev используется пара полей с другими именами, разными в разных списках. Однако при доступе к членам объектов с помощью оператора «квадратные скобки» вместо «точки» компилятор V8 не может выполнить важные оптимизации, поэтому код работает медленнее.

Призовые места получили те участники, которые использовали самомодифицирующийся код. Если в реализации списка заменить idleNext и idlePrev другими именами, а затем заставить интерпретатор исполнять полученный код (использующий оператор «точка»), производительность не падает.

Подробности о том, как и за что мы присуждали баллы участникам, а также все решения, которые мы получили, — в репозитории на GitHub. Поздравлем победителей!

  1. Сергей Шпак — приз 1500 USD
  2. Ори Шалев — приз 1000 USD
  3. Александр Лякшев — приз 500 USD

Отдельно мы решили отметить самых младших участников — одному из них 12, а другому 15 лет. Их команда заняла седьмое место. Дмитрий и Руслан получили особый приз — 350 USD.

Уже думаем над задачей для следующего конкурса.

Комментарии (4)


  1. dmomen
    20.07.2015 15:25

    Поправьте если я не прав, но V8 плевать на операторы. или [], т.к. он использует статистику в рантайме. Есть пруф, что V8 не оптимизирует оператор []?


    1. feldgendler Автор
      20.07.2015 15:42
      +1

      Нет ничего удивительного в том, что obj.member лучше поддаётся оптимизации, чем obj[memberName], потому что каждый раз неизвестно, какое значение лежит в переменной memberName. Первое может быть скомпилировано в доступ по константному смещению в объекте, а второе всегда должно быть готово к любому значению memberName.

      Измерения скорости это подтверждают.


  1. dmomen
    21.07.2015 15:11

    Все еще сомневаюсь, т.к. это противоречит тому, что я вынес из лекции Ильи Климова на fdconf: www.youtube.com/watch?v=ZAJmJmKWNPw
    Оптимизации поддаются поколения объектов с одинаковой структурой. Да, если постоянно менять структуру объекта с помощью [], то он будет выкидываться из оптимизации. Но если поля объекта неизменны с момента создания, то разницы между. и [] быть не должно.


    1. feldgendler Автор
      21.07.2015 15:45

      Да, объекты с одинаковой структурой будут иметь одинаковое компактное представление в памяти. А вот код obj[memberName] должен скомпилироваться в некоторую конструкцию, которая готова к любому значению переменной memberName.