В комментариях к недавней статье оказалось что, во-первых, этот вопрос кому-то да и интересен, и, во-вторых, существует некоторое количество заблуждений на эту тему. Вводные: нам нужен таймер, на Windows, с точностью порядка 1мс, драйвер при этом мы писать не хотим и решения при исполнении которых процессор попытается радикально ускорить глобальное потепление не приемлем.Есть ли такое решение? Из коробки - нету, но при помощи нехитрых приспособлений наше досадное недоразумение превращается... в точный таймер, конечно же. У нас есть некоторое количество досадных недоразумений системных API которые с каждой новой весией Windows всё сильнее ужимают с целью экономии батареи на ноутбуках, общий обзор можно посмотреть в статье по ссылке в самом начале, с графиками. В целом, можно сказать что сколько-нибудь удовлетворительный тайминг начинается примерно со 100мс, всё что ниже чем 15.6мс за гранью допустимого (по мнению ребят из Microsoft). Да и вообще, 640КБ ну точно хватит всем, правда?Ну а временные промежутки меньше 1мс вообще немыслимы - большинство API даже не принимает таких значений, не говоря уже о корректной работе с ними.Исходя из этого я буду строить своё решение вокруг трех недокументированных функций API Win32: NtQueryTimerResolution, NtSetTimerResolution, NtDelayExecution.Связка из первых двух позволяет добиться разрешения системного таймера меньше 1мс, а третья - воспользоваться этим дополнительным разрешением для сна с точностью менее 1мс. Итак, начнем: я пишу преимущественно на C#, но на любом многих ЯП можно написать всё точно то же самое. Шаг 0: поднимем разрешение до максимального. Начиная с Win10 2004 это разрешение больше не является глобальным так что можно ни в чём себе не отказывать (с другой стороны - если процесс не поднял себе разрешение то оно будет 15.6мс вне зависимости от того что там в "глобальном" параметре). Шаг 1: создадим класс PreciseTimer. Полный код я привести, увы, не могу но общая структура такова: поток с максимальным приоритетом который крутится в while(true) цикле и следущие важные поля: Приметка для людей которые не пишут на C#: Stopwatch это обертка над Win32 методамиQueryPerformanceFrequency и QueryPerformanceCounter, никакой дополнительной магии нету. Шаг 2: выясним сколько же нам спать. И спим! Шаг 3: посмотрим что из этого вышло: запустим таймер на 1 минуту и запишем полученные промежутки времени. Код обвязки был использован тоже из статьи по линку в начале, но, к сожалению, там нет кода чтобы построить те великолепные графики, поэтому... не стреляйте в программиста, он рисует как умеет.Тесты запускались на Ryzen 9 5950X под управлением Win11 версии 22000.469Среднее значение для таймера в 1мс: 1.022мс, stddev = 0.018  Для таймера в 10мс: 10.022мс, stddev = 0.017 Очевидно, что алгоритм можно слегка улучшить учитывая время лага и дожать среднее до целевого, но это тоже останется задачей для пытливых читателей. С загрузкой процессора вопрос интереснее, в целом можно утверждать что обнаружению она не поддается: все утилиты радостно рапортируют о 0% загрузке. Установив вручную Affinity на конкретное ядро процессора ничего интересного тоже не обнаружено: Должен признать что это best case когда циклы сна полностью совпали с таймером. Поскольку код оптимизирован под точность он иногда будет нагружать одно ядро примерно на 30-40%.Тут стоит сразу же уточнить что эта нагрузка для процессоров у которых есть HyperThreading (или аналог) относительно безвредная: гарантируется что в это время второй поток сможет исполняться на том же ядре с минимальным ущербом для производительности. У процессоров без оного ситуация хуже, но тесты на ноутбуках показывают что в плане потребления энергии/тепла ситуация гораздо лучше чем у более грубых решений (while(true) цикл без rep nop, например). Подводя итог: цель достигнута? Мне кажется что ответ "да".Все сниппеты кода вдохновлены реальными событиями и использованы в продакшне. UPD: По просьбам трудящихся произвел замер с осциллографом при помощи USB-Serial кабеля на базе чипа FTDI. Во время измерения использовался break для генерации сигнала. К сожалению, я наткнулся на ограничение частоты в 250Гц из-за чего сгенерировать 500Гц сигнал не удалось и в результате период таймера установлен в 2.48мс для генерации 200Гц сигнала (см результаты выше для понимания куда делись 0.02мс). В целом, осциллограф согласен с полученными ранее результатами - видно что иногда всё-таки бывают выбросы, но, как для софтварного таймера на ОС без гарантий реального времени, результат вполне удовлетворительный. User