Рубрики
Без рубрики

Любопытный случай тестирования производительности Settimeate (0)

Netta Bondy. Любопытный случай тестирования производительности. Все началось на сером дне падения. Небо было облачно, ветер дул, и кто-то сказал

Автор оригинала: FreeCodeCamp Community Member.

Netta Bondy.

(Для полного эффекта, прочитайте в хрипском голосе, окруженном облаком дыма)

Все началось на сером дне падения. Небо было облачно, ветер дул, и кто-то сказал мне, что Setimeate (0) Создает в среднем, задержка 4 мс. Они утверждали, что пришло время, чтобы поп-обратный вызов от стека, на очередь обратного вызова и снова на стек. Я думал, что это звучало рыбным (это немного, вы представляете меня в черно-белых с сигарой во рту). Учитывая, что конвейер рендеринга должен выполнять каждые 16 мс, чтобы позволить гладкие анимации, 4 мс казалось много времени для меня. Очень долгое время.

Несколько наивных тестов в Devtools с Консоль. Время () подтвердил это. Средняя задержка на 20 прогонов составила около 1,5 мс. Конечно, 20 прогонов не имеет достаточного размера выборки, но теперь у меня была точка, чтобы доказать. Я хотел запустить тесты в большем масштабе, который мог бы получить мне более точный ответ. Затем я мог бы, конечно, идти и волна, чтобы в лицо моего коллеги, чтобы доказать, что они были неправы.

Почему еще мы делаем то, что делаем?

Традиционный метод

Сразу же я оказался в горячей воде. Для того, чтобы измерить, как долго это заняло Setimeate (0) Чтобы запустить, мне нужна была функция, которая:

  • сделал снимок текущего времени
  • выполнено сентиментальный
  • затем выкидны сразу, чтобы стек был понятен, и запланированный обратный вызов может работать и рассчитать разницу во времени
  • и мне нужна эта функция, чтобы запустить достаточно большое количество раз, чтобы расчеты были статистически значимыми

Но Go-to Construct для этого – для петли – не будет работать. Поскольку for-loop не очищает стек до тех пор, пока он не выполнил каждый цикл, обратный вызов не будет работать немедленно. Или, чтобы положить его в код, мы получим это:

Проблема здесь была присущей – если бы я хотел бежать сентиментальный Несколько раз автоматически, мне бы сделать это из другого контекста. Но до тех пор, пока я бежал из другого контекста, с момента времени всегда будет дополнительная задержка, я начал тест на время выполнения обратного вызова.

Конечно, я мог бы трудиться, как некоторые из этих доброго детектива, напишите функцию, которая делает то, что мне нужно, а затем скопировать и вставить ее в 10 000 раз. Я бы узнал, что я хотел знать, но казнь будет далеко от изящных. Если бы я собирался потереть это в чужом лице, я бы предпочел сделать это другим способом.

Тогда это пришло ко мне.

Революционный метод

Я мог бы использовать веб-работник.

Веб-работники бегут на другой поток. Итак, если я размещу Сетримс Логика в веб-рабочем, я мог бы назвать это несколько раз. Каждый звонок будет создавать свой собственный контекст выполнения, вызов Сетримс И сразу же выходите на функцию, чтобы обратный вызов мог выполнить. Я с нетерпением ждал, чтобы сделать некоторую работу с веб-работниками.

Пришло время перейти на мой доверенный Возвышенный текст Отказ

Я начал просто тестировать воды. С помощью этого кода в main.js :

Некоторые сантехники здесь, чтобы подготовиться к фактическому тесту, но изначально я просто хотел убедиться, что смогу должным образом общаться с веб-рабочим. Так что это был начальный рабочий.js :

И пока он работал как шарм – он произвел результаты, которые я должен был ожидать, но не был:

Будучи так привыкли к синхронному в JS, я не мог не удивляться этим. Сейчас я видел, мой мозг зарегистрировал ошибку. Но, поскольку каждая петля устанавливает новый веб-работник, и они бегают асинхронно, имеет смысл, что цифры не будут напечатаны в порядке.

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

Что я хотел, для веб-работника OnMessage Функция для регистрации T0 , позвоните Сетримс , а затем немедленно выйдите, чтобы не заблокировать стек. Однако я мог вставить дополнительную функциональность внутри обратного вызова, после того, как установил значение T1 Отказ Я добавил свой PostMessage в обратный вызов, поэтому он не блокирует стек:

А вот main.js код:

Эта версия имеет проблему.

Конечно – поскольку я новичок в веб-рабочих, я не считал это сначала. Но, когда несколько прогонов функции продолжали печать 0 Я подумал, что что-то не было правильно.

Когда я напечатал суммы изнутри OnMessage Я получил свой ответ. Основная функция двигалась синхронно, и не ждала сообщения от работника, чтобы вернуться, поэтому он рассчитывал среднее, прежде чем был сделан веб-сайт.

Быстрое и грязное решение – добавить счетчик и выполнять расчет только тогда, когда счетчик достиг максимального значения. Так вот новый main.js:

А вот результаты:

Главная (10) : 0.1

Главная (100) : 1.41

Главная (1000) : 13.082

Ой. Мой. Ну, это не здорово, это? Что тут происходит?

Я пожертвовал тестирование производительности, чтобы взглянуть внутрь. Я сейчас лежу T0 и T1 Когда они созданы, просто чтобы увидеть, что там происходит.

И результаты:

Оказывается мое ожидание T1 рассчитывается сразу после T0 был также ошибочно. В основном, что ничто о веб-работниках не синхронно означает, что мои самые основные предположения о том, как мой код ведет себя, просто не удерживайте истину. Это сложное слепое место, чтобы увидеть.

Не только это, но даже результаты, которые я получил за Главная (10) и Главная (100) , который первоначально сделал меня очень счастливым и самодовольным, не то, что я мог положиться.

Асинхронность веб-работников также делает их ненадежным доверенным доверенным уведомлением для того, как ведь ведет себя в нашей регулярной стеке. Итак, при измерении производительности Сетримс В веб-работнике дает некоторые интересные результаты, это не результаты, которые отвечают на наш вопрос.

Метод учебника

Я был разочарован … Могу ли я действительно не найти решение ванильного JS, которое оба было бы элегантным и доказать, что мой коллега не так?

А потом я понял – что-то я мог сделать, но мне не понравилось.

Я мог бы позвонить сентиментальный рекурсивно.

Теперь, когда я звоню Главная Это позвонит Testrunner какие меры T0 а затем расписаны обратный вызов. Затем обратный вызов работает сразу, рассчитывает T1 а затем звонит Testrunner Опять же, пока не достиг желаемого количества звонков.

Результаты этого кода были особенно удивительными. Вот некоторые распечатки Главная (10) и Главная (1000) :

Результаты значительно отличаются при вызове функции в 1000 раз по сравнению с его вызовом в 10 раз. Я пробовал это неоднократно и во многом получил одинаковые результаты, с Главная (10) входит в 3-4 мс, а Главная (1000) Topping 5 мс.

Если честно, я не уверен, что здесь происходит. Я искал ответ, но не мог найти разумное объяснение. Если вы читаете это и получите образованный догадка о том, что происходит – я хотел бы услышать от вас в комментариях.

Проверенный и истинный метод

Где-то в глубине моего разума, я всегда знал, что это придет к этому … Flargy вещи приятно для тех, кто может их получить, но пробовал и правда всегда будет там в тогдашнем конце. Хотя я пытался избежать этого, я всегда знал, что это вариант. Setinterval Отказ

Этот код делает трюк с несколько грубой силой. Setinterval Запускает функцию несколько раз, ожидание 50 мс между каждым прогоном, чтобы убедиться, что стек понятен. Это неелегант, но тестирует именно то, что мне нужно.

И результаты были также перспективными. Времена, кажется, соответствуют моему первоначальному ожиданию – до 1,5 мс.

Наконец я мог бы поставить этот случай спать. У меня были некоторые взлеты и падения, и моя доля неожиданных результатов, но в конце концов только одна вещь имеет значение – я доказал неправильный разработчик не так! Это было достаточно хорошо для меня.

Хотите поиграть с этим кодом? Проверьте это здесь: https://github.com/nettab/settimeout-test.

Оригинал: “https://www.freecodecamp.org/news/the-curious-case-of-performance-testing-settimeout-0-347059a28acf/”