Синтаксический сахар для синхронизации блока кода в C++

Методы синхронизации блока кода в C++ хорошо документированы, например: здесь и здесь.

В ответах на связанные вопросы нам обычно нужно написать несколько строк кода в начале и конце блока кода, синхронизируемого для запуска и остановки таймера, а затем вычислить прошедшее время. Для удобства можно создать функцию синхронизации, а затем передать блок кода как функцию.

Однако мне любопытно посмотреть, можно ли сделать это еще проще с помощью некоторого синтаксического сахара, который позволит мне синхронизировать блок кода, больше похожий на блок if или while, например,

// some code

time_this_block {

    // code to time

}

// some code

Таким образом, мне не нужно будет помещать // code to time в отдельную функцию, а затем передавать ее в функцию таймера, а также мне не нужно будет создавать различные переменные std::chrono каждый раз, когда я хочу запланировать блок. Я могу просто ввести time_this_block со скобками старт/стоп, и всё. time_this_block (оператор? операция? макрос?) будет иметь определенное предопределенное поведение, например. выведите прошедшее время на стандартный вывод.

Возможно ли это или что-то подобное? Если да, то как?

Если вы создадите класс из time_this_block с измерением первой точки времени в конструкторе и измерением второй точки времени в деструкторе, вы можете поместить объект в фигурные скобки и добиться того же. Например. { time_point_lock мср; //остальная часть кода, которую нужно измерить }

gast128 16.08.2024 09:27

Это можно сделать с помощью класса RAII и лямбды. RAIIClass([]{ /* code to time */ });

3CxEZiVlQ 16.08.2024 09:28
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
2
104
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Ответ принят как подходящий

Для измерения вы можете использовать класс 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

Живая демонстрация

Примечания:

  1. Если вам нужно измерение с более высоким разрешением, вы можете изменить milliseconds на nanoseconds.
  2. Если у вас есть много блоков, которые вы хотите измерить, вы можете добавить параметр string в конструктор BlockTimer с именем/описанием блока, сохранить его в элементе, а затем использовать его для настройки печати измерений в деструкторе.
  3. Неплохим улучшением было бы добавление флага bEnablebool к BlockTimer, который позволит вам легко отключить измерения (например, для производства или разработки).
    Этот флаг может быть либо параметром шаблона (если вы можете разрешить его во время компиляции), либо параметром конструктора (для назначения члену), если вы хотите, чтобы он определялся во время выполнения. Затем вы можете использовать флаг с if (или if constexpr, если это константа времени компиляции), чтобы выполнить условное измерение.
    Живая демо-версия с bEnable, определяемая во время компиляции.

Это потрясающе. Спасибо

josh_eime 16.08.2024 20:27

Рад помочь @josh_eime!

wohlstad 16.08.2024 20:28

Да, вы можете получить именно этот синтаксис с помощью макроса. (Хороша ли это идея, решать вам.)

#define time_this_block if (MyTimerClass timer{}; false) {} else

Где MyTimerClass - это класс, который измеряет время между его созданием и разрушением (например, то, что @wohlstad's ответ использует).

time_this_block{...} расширяется до if (MyTimerClass timer{}; false) {} else {...}, который создает MyTimerClass, запускает ветку else, а затем уничтожает ее.

Хороший трюк +1, хотя я не люблю использовать макросы, когда в этом нет необходимости, и лично предпочитаю явный блок, как я показал в своем ответе.

wohlstad 16.08.2024 09:41

@wohlstad Хм, я бы тоже не стал использовать это в данном случае.

HolyBlackCat 16.08.2024 09:51

Это тоже очень здорово, +1, спасибо

josh_eime 16.08.2024 20:29

@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 мне нравится гораздо больше. Это более элегантно и чисто. При этом мне больше всего нравится ответ Вольштадта: вообще никакого макроса.

Lex W. 16.08.2024 10:07

а как насчет времени создания/разрушения класса BlockTimer? мой макрос этого не измеряет.

Prog_rez 16.08.2024 10:27

@Prog_rez, ваш код также не измеряет время, необходимое для сбора таймингов и их вывода. В распространенных реализациях время, необходимое для создания и уничтожения объекта с автоматическим сроком хранения, идентично времени, необходимому для выполнения операторов в конструкторе и деструкторе, т. е. ваш макрос не быстрее.

Caleth 16.08.2024 10:48

Другие вопросы по теме

C++ Существует ли быстрый многомерный массив, который позволяет использовать подмассивы разного размера?
Обеспечивают ли левый и правый сдвиг лучшую производительность по сравнению с операциями умножения и деления?
Есть ли дополнительная операция при использовании сокращения отрицательного числа в C#?
Excel: более эффективный способ проверки нескольких И в функции ИЛИ
NumPy на небольших массивах: производительность элементарных арифметических операций
Мое приложение React Native больше не запускается, когда я запускаю: npm run android
Следует ли избегать практики распределения памяти, которая приводит к одному вызову malloc?
Что привело к тому, что Python 3.13-0b3 (скомпилированный с отключенным GIL) работал медленнее, чем 3.12.0?
Каков более быстрый способ использования Pandas для создания .loc в большом кадре данных?
Быстрый (самый) способ обработки расширяющейся линейной последовательности в Python

Похожие вопросы

Как ограничить функцию шаблона определенными типами?
Visual Studio C++: копирование проектов и решений с одного компьютера на другой (github не работает)
Странное поведение кнопки EnableWindow при нажатии
Можно ли с уверенностью предположить, что 32-битные числа с плавающей запятой можно напрямую сравнивать друг с другом, если значение соответствует мантиссе?
Практическое руководство: функция C++, которая настраивает тип возвращаемого значения в соответствии с потребностями вызывающей стороны
Возвращает ли low_bound() один и тот же результат с обратными итераторами вектора в порядке возрастания и прямыми итераторами вектора в порядке убывания?
Почему std::make_format_args ожидает неконстантную ссылку
C++ Существует ли быстрый многомерный массив, который позволяет использовать подмассивы разного размера?
Необходим ли std::atomic или voluty при установке переменных из обработчика сигналов?
Могу ли я вызвать CreateString встроенным при создании таблицы?