Измерение времени в C++: практическое руководство по std::chrono для начинающих
Запрос «измерение времени в C++» стабильно популярен у начинающих и продолжающих разработчиков. Часто нужно понять, сколько работает алгоритм, где узкое место или как корректно реализовать таймаут. Стандартная библиотека предлагает для этого мощный и кроссплатформенный инструмент — std::chrono. Разберёмся, как им пользоваться безопасно и удобно на практике.
Какие часы выбрать: system_clock, steady_clock или high_resolution_clock
В <chrono> есть несколько «часов». Коротко о главных:
- std::steady_clock — монотонные часы: не идут назад, не подвержены изменению системного времени. Выбор №1 для измерения длительностей.
- std::system_clock — «настенные» часы: отражают реальное (календарное) время и могут скакать из-за изменения системного времени. Подходят для отметок времени, но не для измерения интервалов.
- std::high_resolution_clock — максимально доступное разрешение. Часто это alias к одному из выше (зависит от реализации). Для кроссплатформенных измерений лучше предпочесть steady_clock.
Главное правило: не смешивайте разные часы при вычислении разницы (start и end должны быть из одного класса часов).
Базовый пример: измерение времени выполнения функции
#include <iostream>
#include <chrono>
#include <vector>
#include <algorithm>
using namespace std;
using namespace std::chrono;
void heavy_task() {
vector<int> v(2'000'000);
iota(v.begin(), v.end(), 0);
sort(v.begin(), v.end(), greater<>());
}
int main() {
auto start = steady_clock::now();
heavy_task();
auto end = steady_clock::now();
auto ms = duration_cast<milliseconds>(end - start).count();
cout << "heavy_task заняла " << ms << " мс\n";
}
Мы использовали steady_clock и перевели разницу во время в миллисекунды через duration_cast<milliseconds>. Для более точной печати в секундах — используйте duration<double>:
auto sec = duration<double>(end - start).count();
cout << fixed << setprecision(6)
<< "Время: " << sec << " с\n";
Удобные литералы и конвертации длительностей
С C++14 появились литералы длительностей: ms, s, ns и т. д. Подключите их и пишите код выразительно:
using namespace std::chrono_literals;
auto d1 = 250ms; // milliseconds
auto d2 = 2s; // seconds
auto total = d1 + d2; // Сумма длительностей — OK
cout << duration_cast<milliseconds>(total).count() << " мс\n";
Золотое правило: для вывода в дробных секундах делайте duration<double>, а не переводите в целые миллисекунды — иначе потеряете точность.
Scope‑таймер: измеряем блок кода «автоматом»
Небольшой класс, который замеряет время между созданием и уничтожением объекта. Удобно для быстрой диагностики (и безопасно при выходе по исключению).
#include <string>
class ScopeTimer {
public:
explicit ScopeTimer(string name)
: name_(std::move(name)), start_(steady_clock::now()) {}
~ScopeTimer() {
auto end = steady_clock::now();
auto ms = duration_cast<milliseconds>(end - start_).count();
cerr << name_ << ": " << ms << " мс\n";
}
private:
string name_;
steady_clock::time_point start_;
};
int main() {
ScopeTimer t("overall");
heavy_task();
}
Советы: выводите в cerr (он не буферизуется как cout), или собирайте статистику и выводите позже. Для крупных проектов лучше внедрить логирование вместо прямого вывода с деструктора.
Паузы и таймауты: sleep_for и sleep_until
Для задержек используйте std::this_thread::sleep_for или sleep_until. Пример с литералами:
#include <thread>
int main() {
using namespace std::chrono_literals;
auto start = steady_clock::now();
std::this_thread::sleep_for(150ms);
auto end = steady_clock::now();
cout << duration_cast<milliseconds>(end - start).count() << " мс\n";
}
Для ожиданий и таймаутов в синхронизации применяйте steady_clock — системное время может измениться, а монотонные часы — нет:
#include <mutex>
#include <condition_variable>
mutex mtx;
condition_variable cv;
bool ready = false;
int main() {
unique_lock<mutex> lk(mtx);
auto deadline = steady_clock::now() + 500ms;
bool ok = cv.wait_until(lk, deadline, []{ return ready; });
cout << (ok ? "готово" : "таймаут") << '\n';
}
Частые ошибки при измерении времени в C++
- Смешивание часов: start из
system_clock, end изsteady_clock— неопределённое поведение. Всегда используйте однотипные часы. - Измерение через system_clock: системное время может «скакать». Для длительности берите
steady_clock. - Потеря точности: приведение к целым миллисекундам преждевременно. Для точных значений используйте
duration<double>в секундах или миллисекундах. - Замер с выводом внутри измеряемого участка: I/O медленный и исказит результат. Выводите после замера или считайте среднее по многим прогоном.
- Без «прогрева» и оптимизаций компилятора: включайте оптимизации (
-O2/-O3), прогревайте код (несколько холостых прогонов), рассчитывайте медиану/перцентили, а не единичный замер. - Случайные перерывы ОС: на многозадачных системах шум неизбежен. Делайте серию измерений и усредняйте.
Небольшие утилиты для удобства
template <class Rep, class Period>
double to_seconds(chrono::duration<Rep, Period> d) {
return chrono::duration<double>(d).count();
}
int main() {
auto start = chrono::steady_clock::now();
heavy_task();
auto end = chrono::steady_clock::now();
cout << fixed << setprecision(6)
<< "Секунд: " << to_seconds(end - start) << '\n';
}
Такой хелпер избавляет от лишних duration_cast и делает код чище и безопаснее для точных измерений.
Чек‑лист: «измерение времени в C++» без ошибок
- Для длительностей — std::steady_clock.
- Не смешивайте типы часов.
- Для вывода дробных значений используйте duration<double>.
- Избегайте I/O внутри измеряемого участка, делайте серию прогонов.
- Для задержек и таймаутов — sleep_for, sleep_until, wait_for, wait_until на steady_clock.
Что дальше изучить
Если вы хотите системно прокачать основы C++ (включая работу со стандартной библиотекой, практику и проекты), посмотрите курс: Освоить C++ от нуля до уверенного уровня — курс «Программирование на C++ с Нуля до Гуру».
Теперь у вас есть рабочий набор приёмов для «измерение времени в C++» на базе std::chrono. Применяйте их в бенчмаркинге, диагностике и грамотной работе с таймаутами — и ваши эксперименты станут точнее и воспроизводимее.
-
Создано 26.01.2026 17:01:57
-
Михаил Русаков

Комментарии (0):
Для добавления комментариев надо войти в систему.
Если Вы ещё не зарегистрированы на сайте, то сначала зарегистрируйтесь.