C++基础教程面向对象(学习笔记(16))

定时代码

在编写代码时,有时候您会遇到一些情况,即您不确定某种方法或其他方法的性能是否更高。那你要怎么说呢?

一种简单的方法是为代码计时,看看运行需要多长时间。C ++ 11在chrono库中附带了一些功能来实现这一点。但是,使用chrono库有点神秘。好消息是,我们可以轻松地将所需的所有计时功能封装到一个类中,然后我们可以在自己的程序中使用它们。

这是类:

#include <chrono> // 为std::chrono 函数
 
class Timer
{
private:
	// 键入别名可以更轻松地访问嵌套类型
	using clock_t = std::chrono::high_resolution_clock;
	using second_t = std::chrono::duration<double, std::ratio<1> >;
	
	std::chrono::time_point<clock_t> m_beg;
 
public:
	Timer() : m_beg(clock_t::now())
	{
	}
	
	void reset()
	{
		m_beg = clock_t::now();
	}
	
	double elapsed() const
	{
		return std::chrono::duration_cast<second_t>(clock_t::now() - m_beg).count();
	}
};

而已!要使用它,我们在main函数的顶部(或者我们想要开始计时的任何地方)实例化一个Timer对象,然后每当我们想知道程序运行到该点的时间时调用elapsed()成员函数。 。

int main()
{
    Timer t;
 
    // 代码耗费的时间就
 
    std::cout << "Time elapsed: " << t.elapsed() << " seconds\n";
 
    return 0;
}

现在,让我们在一个实际的例子中使用它,我们对10000个元素的数组进行排序。首先,让我们使用我们在前一章中开发的选择排序算法:

#include <iostream>
#include <array>
#include <chrono> // for std::chrono functions
 
const int g_arrayElements = 10000;
 
class Timer
{
private:
	//  键入别名可以更轻松地访问嵌套类型
	using clock_t = std::chrono::high_resolution_clock;
	using second_t = std::chrono::duration<double, std::ratio<1> >;
 
	std::chrono::time_point<clock_t> m_beg;
 
public:
	Timer() : m_beg(clock_t::now())
	{
	}
 
	void reset()
	{
		m_beg = clock_t::now();
	}
 
	double elapsed() const
	{
		return std::chrono::duration_cast<second_t>(clock_t::now() - m_beg).count();
	}
};
 
void sortArray(std::array<int, g_arrayElements> &array)
{
 
	// 逐步完成数组的每个元素
	// (除了最后一个,我们到达那里时已经排序了)
	for (int startIndex = 0; startIndex < g_arrayElements - 1; ++startIndex)
	{
		// smallestIndex是我们遇到此迭代的最小元素的索引
		// 首先假设最小元素是此迭代的第一个元素
		int smallestIndex = startIndex;
 
		// 然后在数组的其余部分中查找较小的元素
		for (int currentIndex = startIndex + 1; currentIndex < g_arrayElements; ++currentIndex)
		{
			// 如果我们发现的元素小于我们之前发现的最小元素
			if (array[currentIndex] < array[smallestIndex])
				//然后跟踪它
				smallestIndex = currentIndex;
		}
 
		// smallestIndex现在是剩下的数组中最小的元素
		// 将我们的start元素与我们的最小元素交换(将其分类到正确的位置)
		std::swap(array[startIndex], array[smallestIndex]);
	}
}
 
int main()
{
	std::array<int, g_arrayElements> array;
	for (int i = 0; i < g_arrayElements; ++i)
		array[i] = g_arrayElements - i;
 
	Timer t;
 
	sortArray(array);
 
	std::cout << "Time taken: " << t.elapsed() << " seconds\n";
 
	return 0;
}

在作者的机器上,三次运行产生了0.0507,0.0506和0.0498的时间。所以我们可以说大约0.05秒。

现在,让我们使用标准库中的std :: sort进行相同的测试。

#include <iostream>
#include <array>
#include <chrono> // for std::chrono functions
#include <algorithm> // for std::sort
 
const int g_arrayElements = 10000;
 
class Timer
{
private:
	// 键入别名可以更轻松地访问嵌套类型
	using clock_t = std::chrono::high_resolution_clock;
	using second_t = std::chrono::duration<double, std::ratio<1> >;
 
	std::chrono::time_point<clock_t> m_beg;
 
public:
	Timer() : m_beg(clock_t::now())
	{
	}
 
	void reset()
	{
		m_beg = clock_t::now();
	}
 
	double elapsed() const
	{
		return std::chrono::duration_cast<second_t>(clock_t::now() - m_beg).count();
	}
};
 
void sortArray(std::array<int, g_arrayElements> &array)
{
 
	// 逐步完成数组的每个元素
	// (除了最后一个,我们到达那里时已经排序了)
	for (int startIndex = 0; startIndex < g_arrayElements - 1; ++startIndex)
	{
		// smallestIndex是我们遇到此迭代的最小元素的索引
		// 首先假设最小元素是此迭代的第一个元素
		int smallestIndex = startIndex;
 
		// 然后在数组的其余部分中查找较小的元素
		for (int currentIndex = startIndex + 1; currentIndex < g_arrayElements; ++currentIndex)
		{
			// 如果我们发现的元素小于我们之前发现的最小元素
			if (array[currentIndex] < array[smallestIndex])
				// 然后跟踪它
				smallestIndex = currentIndex;
		}
 
		// smallestIndex现在是剩下的数组中最小的元素
		// 将我们的start元素与我们的最小元素交换(将其分类到正确的位置)
		std::swap(array[startIndex], array[smallestIndex]);
	}
}
 
int main()
{
	std::array<int, g_arrayElements> array;
	for (int i = 0; i < g_arrayElements; ++i)
		array[i] = g_arrayElements - i;
 
	Timer t;
 
	std::sort(array.begin(), array.end());
 
	std::cout << "Time taken: " << t.elapsed() << " seconds\n";
 
	return 0;
}

在作者的机器上,这产生了以下结果:0.000693,0.000692和0.000699。所以基本上在0.0007左右。

换句话说,在这种情况下,std :: sort比我们自己写的选择排序快100倍!

关于计时的一些警告

时间很简单,但是你的结果会受到许多事情的显着影响,因此了解这些事情是很重要的。

首先,确保您使用的是发布版本目标,而不是调试版本目标。调试构建目标通常会关闭优化,并且优化可能会对结果产生重大影响。例如,使用调试构建目标,在作者的机器上运行上面的std :: sort示例需要0.0235秒 - 这是33倍的时间!

其次,您的计时结果将受到您的系统可能在后台执行的其他操作的影响。为了获得最佳效果,请确保您的系统没有执行任何CPU或内存密集型操作(例如,玩游戏)或密集型硬盘驱动器(例如搜索文件或运行防病毒扫描)。

然后测量至少3次。如果结果都相似,则取平均值。如果一个或两个结果不同,请再运行一次该程序,直到您更好地了解哪些是异常值。请注意,当您坐在后台的网站在新的广告横幅中旋转并且必须解析一堆javascript时,看似无辜的东西,例如网络浏览器,可以暂时使您的CPU达到100%利用率。多次运行有助于确定您的初始运行是否可能受到此类事件的影响。

第三,在对两组代码进行比较时,要注意可能影响时序的运行之间可能发生的变化。您的系统可能已经在后台启动了防病毒扫描,或者您可能现在正在流式传输音乐。随机化也会影响时间安排。如果我们对填充了随机数的数组进行排序,结果可能会受到随机化的影响。仍然可以使用随机化,但确保使用固定种子(例如,不要使用系统时钟),因此每次运行的随机化都是相同的。此外,请确保您没有等待用户输入的时间,因为用户输入内容的时间不应该是您的时间考虑因素的一部分。

最后,注意,结果仅对您机器的体系结构,操作系统,编译器和系统规格有效。您可能会在具有不同优势和劣势的其他系统上获得不同的结果。

猜你喜欢

转载自blog.csdn.net/qq_41879485/article/details/83012765