Методы синхронизации блока кода в C++ хорошо документированы, например: здесь и здесь.
В ответах на связанные вопросы нам обычно нужно написать несколько строк кода в начале и конце блока кода, синхронизируемого для запуска и остановки таймера, а затем вычислить прошедшее время. Для удобства можно создать функцию синхронизации, а затем передать блок кода как функцию.
Однако мне любопытно посмотреть, можно ли сделать это еще проще с помощью некоторого синтаксического сахара, который позволит мне синхронизировать блок кода, больше похожий на блок if
или while
, например,
// some code
time_this_block {
// code to time
}
// some code
Таким образом, мне не нужно будет помещать // code to time
в отдельную функцию, а затем передавать ее в функцию таймера, а также мне не нужно будет создавать различные переменные std::chrono
каждый раз, когда я хочу запланировать блок. Я могу просто ввести time_this_block
со скобками старт/стоп, и всё. time_this_block
(оператор? операция? макрос?) будет иметь определенное предопределенное поведение, например. выведите прошедшее время на стандартный вывод.
Возможно ли это или что-то подобное? Если да, то как?
Это можно сделать с помощью класса RAII и лямбды. RAIIClass([]{ /* code to time */ });
Для измерения вы можете использовать класс RAII.
Что-то вроде:
#include <chrono>
#include <iostream>
class BlockTimer {
public:
BlockTimer() {
m_start = std::chrono::steady_clock::now();
}
~BlockTimer() {
auto end = std::chrono::steady_clock::now();
auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - m_start);
std::cout << "duration (ms): " << duration.count() << "\n";
}
private:
std::chrono::steady_clock::time_point m_start;
};
Затем используйте его следующим образом:
{
BlockTimer btimer;
// ... some code
} // here the scope of `btimer` will end and it will report the duration of the block
Примечания:
milliseconds
на nanoseconds
.string
в конструктор BlockTimer
с именем/описанием блока, сохранить его в элементе, а затем использовать его для настройки печати измерений в деструкторе.bEnable
bool
к BlockTimer
, который позволит вам легко отключить измерения (например, для производства или разработки).if
(или if constexpr
, если это константа времени компиляции), чтобы выполнить условное измерение.Это потрясающе. Спасибо
Рад помочь @josh_eime!
Да, вы можете получить именно этот синтаксис с помощью макроса. (Хороша ли это идея, решать вам.)
#define time_this_block if (MyTimerClass timer{}; false) {} else
Где MyTimerClass
- это класс, который измеряет время между его созданием и разрушением (например, то, что @wohlstad's ответ использует).
time_this_block{...}
расширяется до if (MyTimerClass timer{}; false) {} else {...}
, который создает MyTimerClass
, запускает ветку else
, а затем уничтожает ее.
Хороший трюк +1, хотя я не люблю использовать макросы, когда в этом нет необходимости, и лично предпочитаю явный блок, как я показал в своем ответе.
@wohlstad Хм, я бы тоже не стал использовать это в данном случае.
Это тоже очень здорово, +1, спасибо
@wohlstad ответ очень красивый. но что сообщество может сказать об этом решении? я определяю новый макрос в файле *.h следующим образом
#pragma once
#include <chrono>
#include <iostream>
#define time_this_block(code_marker, code_to_time) \
\
{ \
auto t1 = std::chrono::high_resolution_clock::now(); \
code_to_time; \
auto t2 = std::chrono::high_resolution_clock::now(); \
auto ms_int = std::chrono::duration_cast<std::chrono::milliseconds>(t2 - t1); \
std::chrono::duration<double, std::milli> ms_double = t2 - t1; \
std::cout << code_marker << " runs " << ms_double.count() << "ms" << std::endl; \
}
и после использования этого макроса, как указано ниже:
#include "time_this_block.h"
void long_operation()
{
//some code
}
int main()
{
time_this_block("mark1", long_operation();)
return 0;
}
Я использовал макрос, почти идентичный этому (только другие классы таймеров вместо std::chrono) более 15 лет назад, но макрос HolyBlackCat мне нравится гораздо больше. Это более элегантно и чисто. При этом мне больше всего нравится ответ Вольштадта: вообще никакого макроса.
а как насчет времени создания/разрушения класса BlockTimer? мой макрос этого не измеряет.
@Prog_rez, ваш код также не измеряет время, необходимое для сбора таймингов и их вывода. В распространенных реализациях время, необходимое для создания и уничтожения объекта с автоматическим сроком хранения, идентично времени, необходимому для выполнения операторов в конструкторе и деструкторе, т. е. ваш макрос не быстрее.
Если вы создадите класс из time_this_block с измерением первой точки времени в конструкторе и измерением второй точки времени в деструкторе, вы можете поместить объект в фигурные скобки и добиться того же. Например. { time_point_lock мср; //остальная часть кода, которую нужно измерить }