C++ 中的时序逻辑错误(使用 std::chrono)
Posted
技术标签:
【中文标题】C++ 中的时序逻辑错误(使用 std::chrono)【英文标题】:Logical error in timing in C++ (using std::chrono) 【发布时间】:2019-10-03 13:46:49 【问题描述】:我编写了一个 C++ 程序来对各种排序算法进行基准测试,以找出哪一个是最快的。但是,我在执行代码时遇到了一些问题。
我首先创建了一个类来使用构造函数和析构函数对算法进行计时。然后我使用std::chrono::time_point_cast
将时间显式转换为毫秒。但是,每次我运行我的程序时,程序最终都会显示零毫秒。
请注意,我已经包含了 chrono 头文件。
这是涉及的程序源代码部分。
类定义
int Array[20], size = 20;
class BenchmarkTimer
public:
std::chrono::time_point<std::chrono::high_resolution_clock> startpt;
float ms;
long long duration;
BenchmarkTimer() : ms(0), duration(0)
startpt = std::chrono::high_resolution_clock::now();
~BenchmarkTimer()
auto endpt = std::chrono::high_resolution_clock::now();
auto init = std::chrono::time_point_cast<std::chrono::milliseconds>(startpt).time_since_epoch().count();
auto final = std::chrono::time_point_cast<std::chrono::milliseconds>(endpt).time_since_epoch().count();
auto duration = final - init;
;
选择排序功能(这只是众多排序算法中的一种)。
void SelectionSort(int Array[])
BenchmarkTimer timer;
int temp, smallest, position, j;
for (int i = 0; i < size - 1; i++)
smallest = Array[i];
position = i;
for (j = i + 1; j < size; j++)
if (Array[j] < smallest)
smallest = Array[j];
position = j;
temp = Array[i];
Array[i] = Array[position];
Array[position] = temp;
DisplayArray(Array);
std::cout << "\nTime taken to sort the array: " << timer.duration << " ms" << std::endl;
DisplayArray(Array)
函数调用只是将数组显示在屏幕上。
我希望程序显示经过的毫秒数。
现在,实际输出是:
Time taken to sort the array: 0 ms
但我希望输出是:
Time taken to sort the array: 13 ms
(13 毫秒只是一个例子。)
我建议你建议更简单的解决方案,因为我处于 C++ 编程的中级水平。
提前致谢!
【问题讨论】:
是的,我做到了。我什至尝试过使用nanoseconds
。
你在析构函数中计算了持续时间,当你调用timer.duration
时析构函数还没有被调用。在一个名为 get_elapsed_time()
的函数中移动析构函数代码,该函数返回属性 duration
【参考方案1】:
你的问题是你只在BenchmarkTimer
的析构函数中计算时间。这意味着duration
将始终为 0,因为它仅在析构函数中发生变化,并且在对象被析构后您无法访问该对象。
有几种方法可以解决此问题。第一种是将时序代码移到函数中。其次,您可以修改BenchmarkTimer
以在构造函数中获取一个函数对象,该对象将是要运行的代码,然后在构造函数中进行计算。看起来像
class BenchmarkTimer
public:
std::chrono::time_point<std::chrono::high_resolution_clock> startpt;
float ms;
long long duration;
template<typename Func>
BenchmarkTimer(Func func) : ms(0), duration(0)
startpt = std::chrono::high_resolution_clock::now();
func();
auto endpt = std::chrono::high_resolution_clock::now();
auto diff = end-start;
duration = diff.count();
;
void SelectionSort(int Array[])
BenchmarkTimer timer([&]()
int temp, smallest, position, j;
for (int i = 0; i < size - 1; i++)
smallest = Array[i];
position = i;
for (j = i + 1; j < size; j++)
if (Array[j] < smallest)
smallest = Array[j];
position = j;
temp = Array[i];
Array[i] = Array[position];
Array[position] = temp;
);
DisplayArray(Array);
std::cout << "\nTime taken to sort the array: " << timer.duration << " ms" << std::endl;
另一种选择是将另一个函数添加到BenchmarkTimer
,一旦你希望它进行计算,你就会调用它,并将你的析构函数代码移动到那里。请注意这一点,因为在您的析构函数中声明了一个隐藏类的duration
的duration
变量。代码应该是这样的
auto endpt = std::chrono::high_resolution_clock::now();
auto init = std::chrono::time_point_cast<std::chrono::milliseconds>(startpt).time_since_epoch().count();
auto final = std::chrono::time_point_cast<std::chrono::milliseconds>(endpt).time_since_epoch().count();
duration = final - init;
// ^ no auto here
【讨论】:
我希望我能采纳这个建议,但我发现它有点高级。我宁愿发现 rafix07 的建议是一个更简单但可行的替代方案。不过,感谢您的建议。 @MithunK 没问题。希望有一天你会看到这段代码,而不是认为它是如此先进。如果您好奇,我们有很多书籍here 讨论现代 C++ 和模板。它们在某些时候值得一读。 感谢您分享链接。【参考方案2】:解决这个问题的一个非常简单的方法是将计时器的打印语句放在~BenchmarkTimer()
中。 BenchmarkTimer
构造函数可以接收一条消息来增加~BenchmarkTimer()
中的输出。这可能看起来像:
class BenchmarkTimer
public:
std::string msg_;
std::chrono::steady_clock::time_point startpt_;
explicit BenchmarkTimer(std::string msg)
: msg_(std::move(msg))
, startpt_(std::chrono::steady_clock::now())
~BenchmarkTimer()
using namespace std::chrono;
auto endpt = steady_clock::now();
std::cout << msg_ << duration_cast<milliseconds>(endpt - startpt_).count() << " ms\n";
BenchmarkTimer(BenchmarkTimer const&) = delete;
BenchmarkTimer& operator=(BenchmarkTimer const&) = delete;
;
您可以通过在要开始计时的点构造BenchmarkTimer
来使用它,并带有适当的消息,它将记录并记录计时器范围内的时间。例如:
void SelectionSort(int Array[])
BenchmarkTimer timer"\nTime taken to sort the array: ";
int temp, smallest, position, j;
// ...
DisplayArray(Array);
// Output: Time taken to sort the array: 13 ms
【讨论】:
explicit
关键字有什么用?
它可以防止 std::string
隐式转换为 BenchmarkTimer
。相反,必须使用 explicit 语法,如SelectionSort
中的示例使用所示。我可能还应该修改我的答案以给 BenchmarkTimer
删除的副本成员,因为延长 BenchmarkTimer
对象的生命周期是不寻常的(并且可能是一个错误)。以上是关于C++ 中的时序逻辑错误(使用 std::chrono)的主要内容,如果未能解决你的问题,请参考以下文章