C++ 时间测量看起来太慢了
Posted
技术标签:
【中文标题】C++ 时间测量看起来太慢了【英文标题】:C++ time measurement looks too slow 【发布时间】:2017-05-02 19:01:55 【问题描述】:我正在使用 OpenGL GLUT 代码编写游戏,并且我正在应用一种游戏开发技术,该技术包括测量游戏主循环的每次迭代所消耗的时间,因此您可以使用它来按比例更新游戏场景上次更新了。为了实现这一点,我在循环开始时有这个:
void logicLoop ()
float finalTime = (float) clock() / CLOCKS_PER_SEC;
float deltaTime = finalTime - initialTime;
initialTime = finalTime;
...
// Here I move things using deltaTime value
...
当我在游戏中添加子弹时,问题就来了。如果子弹在两秒钟内没有击中任何目标,则必须将其摧毁。然后,我所做的就是保持对创建子弹的那一刻的引用,如下所示:
class Bullet: public GameObject
float birthday;
public:
Bullet ()
...
// Some initialization staff
...
birthday = (float) clock() / CLOCKS_PER_SEC;
float getBirthday () return birthday;
然后我在 finalTime 和 deltaTime 测量之外添加了这个逻辑:
if (bullet != NULL)
if (finalTime - bullet->getBirthday() > 2)
world.remove(bullet);
bullet = NULL;
看起来不错,但是当我运行代码时,子弹的存活时间太长了。寻找问题所在,我打印了 (finalTime - bullet->getBirthday()) 的值,我发现它的增长非常缓慢,就像它不是以秒为单位的时间一样。
问题出在哪里?我以为结果会在几秒钟内,所以子弹会在两秒钟内被移除。
【问题讨论】:
不确定这里发生了什么,但如果你有 C++11,你可以尝试使用<chrono>
并在项目符号中存储 std::chrono::time_point
。
为什么不使用glutGet(GLUT_ELAPSED_TIME)
?
@genpfault:虽然看起来很可能而且很明显,但请确保文档没有说明;那是挂墙时间,是吗?
【参考方案1】:
这是一个常见的错误。 clock()
不测量实际时间的流逝;它测量 CPU 运行这个特定进程时已经过去了多少时间。
其他进程也占用CPU时间,所以两个时钟不一样。每当您的操作系统正在执行某个其他进程的代码时,包括当这个“睡眠”时,都不算在clock()
中。如果您的程序在具有多个 CPU 的系统上是多线程的,clock()
可能会“重复计算”时间!
人类对操作系统时间片一无所知或感知:我们只是感知实际时间的实际流逝(称为“墙上时间”)。最终,您将看到 clock()
的时基与挂钟时间不同。
Do not use clock()
to measure wall time!
你想要gettimeofday()
或clock_gettime()
之类的东西。为了减轻人们更改系统时间的影响,在 Linux 上,我个人推荐 clock_gettime()
使用系统的“单调时钟”,该时钟与墙上时间同步,但具有不受人们玩耍影响的任意纪元电脑时间设置。 (如果需要,显然切换到便携式替代品。)
这个其实在the cppreference.com page for clock()
讨论过:
std::clock
时间可能会比挂钟快或慢,这取决于操作系统给予程序的执行资源。例如,如果 CPU 由其他进程共享,std::clock
时间可能会比挂钟慢。另一方面,如果当前进程是多线程的并且有多个执行内核可用,std::clock
时间可能会比挂钟快。
当您不确定发生了什么时,请养成阅读您使用的所有功能的文档的习惯。
编辑:原来 GLUT 本身有一个你可以使用的功能,这可能很方便。 glutGet(GLUT_ELAPSED_TIME)
为您提供自您致电 glutInit()
以来经过的墙毫秒数。所以我想这就是你需要的。它的性能可能稍高一些,特别是如果 GLUT(或 OpenGL 的其他部分)已经定期请求挂起时间,并且如果此函数仅查询已经获得的时间……从而使您免于不必要的第二次系统调用(成本) .
【讨论】:
这是正确答案。在低延迟系统中,我们还使用clock_gettime
为我们的应用程序计时。【参考方案2】:
如果您在 Windows 上,您可以使用 QueryPerformanceFrequency / QueryPerformanceCounter,它可以提供非常准确的时间测量。
这是一个例子。
#include <Windows.h>
using namespace std;
int main()
LARGE_INTEGER freq = 0, 0;
QueryPerformanceFrequency(&freq);
LARGE_INTEGER startTime = 0, 0;
QueryPerformanceCounter(&startTime);
// STUFF.
for(size_t i = 0; i < 100; ++i)
cout << i << endl;
LARGE_INTEGER stopTime = 0, 0;
QueryPerformanceCounter(&stopTime);
const double ellapsed = ((double)stopTime.QuadPart - (double)startTime.QuadPart) / freq.QuadPart;
cout << "Ellapsed: " << ellapsed << endl;
return 0;
【讨论】:
很难确定,因为 MSDN 太差了,但这个 似乎 是独立于进程且稳定的,因此在 Windows 上是一个不错的选择。以上是关于C++ 时间测量看起来太慢了的主要内容,如果未能解决你的问题,请参考以下文章