簡體   English   中英

使用 C++14 lambda 測量任意函數的執行時間

[英]Measure execution time of arbitrary functions with C++14 lambda

Scott Meyer 的書“Effective Modern C++”中的第 24 條讓我很興奮。 他提到了編寫 C++14 lambda 來記錄任意函數調用所用時間的可能性。

我仍處於學習 C++14 功能的早期階段。 我的嘗試 (Main.cpp) 看起來像這樣用於測量成員函數調用的時間:

#include <chrono>
#include <iostream>

auto measure = [](auto&& function, auto&&... parameters) -> decltype(function)
{
    const std::chrono::steady_clock::time_point startTimePoint =
    std::chrono::steady_clock::now();

    const auto returnValue = std::forward<decltype(function)>(function)(
            std::forward<decltype(parameters)>(parameters)...);

    const std::chrono::steady_clock::time_point stopTimePoint =
    std::chrono::steady_clock::now();

    const std::chrono::duration<double> timeSpan = std::chrono::duration_cast<
    std::chrono::duration<double>>(stopTimePoint - startTimePoint);

    std::cout << "Computation took " << timeSpan.count()
    << " seconds." << std::endl;

    return returnValue;
};

class Test
{
public:

    int computation(double dummy)
    {
        std::cout << "Received " << dummy << ". Computing..." << std::endl;

        return 123;
    }
};

int main(int, char**)
{
    Test instance;

    using Function = int (Test::*)(double);
    Function function = instance.computation;

    int result = measure(function, 1.0);

    std::cout << "Result: " << result << std::endl;

    return 0;
}

我收到以下編譯錯誤:

..\src\Main.cpp: In function 'int main(int, char**)':
..\src\Main.cpp:43:36: error: cannot convert 'int (Test::*)(double)' to 'int' in initialization
    int result = measure(function, 1.0);
                                                                        ^
..\src\Main.cpp: In instantiation of '<lambda(auto:1&&, auto:2&& ...)> [with auto:1 = int (Test::*&)(double); auto:2 = {double}; decltype (function) = int (Test::*&)(double)]':
..\src\Main.cpp:43:36:   required from here
..\src\Main.cpp:9:69: error: must use '.*' or '->*' to call pointer-to-member function in 'std::forward<int (Test::*&)(double)>((* & function)) (...)', e.g. '(... ->* std::forward<int (Test::*&)(double)>((* & function))) (...)'
    const auto returnValue = std::forward<decltype(function)>(function)(
                                                     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^
        std::forward<decltype(parameters)>(parameters)...);
        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~                

顯然我做錯了,但我不知道如何做對。 有誰能夠幫助我? 非常感謝你!

有兩種方法可以完成這項任務。

  1. 接受一個函數(或一個函數對象),返回一個修改后的函數,它做與原始函數相同的事情,加上測量時間。 返回的對象類型不能與接受的參數類型相同。 它必須是 lambda(或自定義類類型,但 lambda 更簡單)。 調用返回的對象時執行實際測量。 使用語法示例:

     result = measure(foo)(param1, param2); // variant 1 auto measured_foo = measure(foo); result = measured_foo(param1, param2); // variant 2
  2. 接受一個函數(或函數對象)及其參數,調用它並執行測量。 返回類型是原始函數的類型。 使用語法示例:

     result = measure(foo, param1, param2);

您的measure最接近第二個變體,唯一有問題是聲明。 這是正確的:

auto measure = [](auto&& function, auto&&... parameters) -> decltype(auto)

准確地說,這不是唯一錯誤的事情。 如果被測函數返回一個引用,返回類型將是錯誤的。 要解決此問題,請更換

const auto returnValue = ...

decltype(auto) returnValue = ...

在 lambda 的主體中

您的程序(但不是measure本身)的另一件事是您嘗試使用成員函數的方式。

Function function = instance.computation;

這是行不通的。 使用 lambda 或std::bind創建綁定成員函數。 關於在 stackoverflow 上執行此操作的正確方法,有無數個問題(和很好的答案)。

現場演示(通過參考工作返回)。

如果您想要創建測量函數的第一種方法,方法如下:

auto measure = [](auto&& function) -> decltype(auto)
{
    return [=](auto&&... parameters) mutable -> decltype(auto) {

        const std::chrono::steady_clock::time_point startTimePoint = 
            std::chrono::steady_clock::now();

        decltype(auto) result = function(std::forward<decltype(parameters)>(parameters)...);

        const std::chrono::steady_clock::time_point stopTimePoint =
            std::chrono::steady_clock::now();

        const std::chrono::duration<double> timeSpan = std::chrono::duration_cast<
        std::chrono::duration<double>>(stopTimePoint - startTimePoint);

        std::cout << "Computation took " << timeSpan.count()
                << " seconds." << std::endl;

        return result;
    };
};

現場演示(通過參考返回)。

特別注意decltype(auto)的宗教用途。 在第二個版本中也是mutable的。

不知道你想在那里做什么,但如果這是你想做的,我在這里猜測我做了什么:

#include <chrono>
#include <iostream>
#include <functional>

auto measure = [](auto function, auto&&... parameters) -> decltype(function(parameters...))
{
    const std::chrono::steady_clock::time_point startTimePoint =
    std::chrono::steady_clock::now();

    auto returnValue = function(parameters...);

    const std::chrono::steady_clock::time_point stopTimePoint =
    std::chrono::steady_clock::now();

    const std::chrono::duration<double> timeSpan = std::chrono::duration_cast<
    std::chrono::duration<double>>(stopTimePoint - startTimePoint);

    std::cout << "Computation took " << timeSpan.count()
    << " seconds." << std::endl;

    return returnValue;
};

class Test
{
public:

    int computation(double dummy)
    {
        std::cout << "Received " << dummy << ". Computing..." << std::endl;

        return 123;
    }
};

int main(int, char**)
{
    Test instance;

    auto func = std::bind(&Test::computation, &instance, std::placeholders::_1);

    int result = measure(func, 1.0);

    std::cout << "Result: " << result << std::endl;

    return 0;
}

如果您出於任何原因不喜歡使用成員函數的函數指針(請參閱此處),那么好的舊宏可以為您提供幫助。 有些人建議盡量減少宏的使用,但在這種情況下,我發現它更直觀、更易讀且更容易。 可以使用以下宏對任意函數(包括調用返回類型的類的公共成員函數)進行計時。

#define timefnrt(W, X, Z){\
    time_t V = time(NULL);\
    W = X;\
    time_t Y = time(NULL);\
    Z = difftime(Y, V);\
};

現場代碼演示

如果函數返回void ,則可以這樣對此類函數進行計時:

#define timefnvoid(X, Z){\
    time_t V = time(NULL);\
    X;\
    time_t Y = time(NULL);\
    Z = difftime(Y, V);\
};

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM