简体   繁体   English

我的毫秒秒表似乎很慢

[英]My millisecond stopwatch seems to be slow

I was bored so I wrote a quick millisecond stopwatch program in C++, but I noticed it was slower than it should be;我很无聊,所以我用 C++ 写了一个快速的毫秒秒表程​​序,但我注意到它比它应该的要慢; that being the data seemed behind actual time.那是数据似乎落后于实际时间。 Here's a look at my simple code.下面看一下我的简单代码。 I assume the console clearing method and/or the delay is slowing it down, but I am not sure of a solution to speed up the program for an accurate time reading.我假设控制台清除方法和/或延迟会减慢它的速度,但我不确定加快程序以获得准确时间读数的解决方案。

#include <chrono>
#include <thread>
#include <Windows.h>
#include <iostream>
#include <fstream>
using namespace std;
using namespace std::this_thread; // sleep_for, sleep_until
using namespace std::chrono; // nanoseconds, system_clock, 
seconds

void DELAY_IN_MILLISECONDS(int millisec) {
    sleep_until(system_clock::now() + milliseconds (millisec));
}
void clearConsole()
{
    system( "CLS");
}
struct Time {
    unsigned int tick = 0;
    unsigned int millisec = 0;
    unsigned int sec = 0;
    unsigned int min = 0;
    unsigned int hr = 0;
    unsigned int days = 0;
} timeAm;

int main()
{
    cout << "Started stopwatch" << endl;
    while (true)
    {
        //listens if user presses stop key
        //stop key is ESC
        //This should also write the time to a textFile

        if (GetKeyState(VK_ESCAPE) & 0x8000)
        {
            ofstream File("time.txt");
            File << "[" << timeAm.hr << " Hours] "
                 << "[" << timeAm.hr << " Minutes]"
                 << "[" << timeAm.min << " Seconds]"
                 << "[" << timeAm.sec << " Milliseconds]";
            File.close();
            return 0;
        }
        DELAY_IN_MILLISECONDS(1); //1 second delay
        //seconds
        timeAm.millisec++;
        //minutes
        if (timeAm.millisec > 59)
        {
            timeAm.millisec = 0;
            timeAm.sec++;
        }
        //hours
        if (timeAm.sec > 59)
        {
            timeAm.sec = 0;
            timeAm.min++;
        }
        //days
        if (timeAm.min > 23)
        {
            timeAm.min = 0;
            timeAm.hr++;
        }
        clearConsole(); //clears console
        //prints to console
        cout << "[" << timeAm.hr << " Hours] "
             << "[" << timeAm.hr << " Minutes]"
             << "[" << timeAm.min << " Seconds]"
             << "[" << timeAm.sec << " Milliseconds]";
    }
}

Your timer makes some incorrect assumptions:您的计时器做出了一些不正确的假设:

  1. (incorrect) Every sleep will be precisely 1ms (不正确)每次睡眠将精确到 1ms

    As described in https://en.cppreference.com/w/cpp/thread/sleep_untilhttps://en.cppreference.com/w/cpp/thread/sleep_until中所述

    The function also may block for longer than until after sleep_time has been reached due to scheduling or resource contention delays.由于调度或资源争用延迟,该函数也可能阻塞更长时间, until达到sleep_time之后。

  2. (incorrect) All other code is executed instantly (takes exactly zero time). (不正确)所有其他代码都立即执行(完全为零时间)。

    Obviously that's a crazy notion.显然这是一个疯狂的想法。 But yet your code at present relies on it.但是你的代码目前依赖它。 It will sleep for 1ms (which as per above we already know might not be actually 1ms), and then increment its millisecond count.它会休眠 1ms(根据上面我们已经知道实际上可能不是 1ms),然后增加它的毫秒计数。 Following that, it does some computation and some I/O before getting back around to the top of the loop to sleep for another "1ms".之后,它会进行一些计算和一些 I/O,然后再回到循环顶部以休眠另一个“1ms”。

    By very definition, if the code between sleeps takes any time whatsoever then your clock will drift.根据定义,如果睡眠之间的代码需要任何时间,那么你的时钟就会漂移。

  3. (incorrect) system_clock is monotonic (不正确) system_clock是单调的

    The documentation explicitly states it is not ( ie the clock can be adjusted at any point in time).文档明确指出它不是(可以随时调整时钟)。 For a monotonic clock designed for this kind of thing, use std::steady_clock instead.对于为这种事情设计的单调时钟,请改用std::steady_clock

So, what approach should you take?那么,您应该采取什么方法呢?

The way timing normally works is you begin with a time_point and then at any time you calculate the time elapsed between then and now.计时通常的工作方式是从time_point开始,然后在任何时候计算从那时到现在所经过的时间。 With some basic math, you can then turn that into HH:MM:SS.mmm .通过一些基本的数学运算,您可以将其转换为HH:MM:SS.mmm

Doing it like this will deal with those first two incorrect assumptions.这样做将处理前两个不正确的假设。 Whenever your process wakes up you can calculate the true elapsed time, independent of how long the other code (or the sleep) took.每当您的进程唤醒时,您都可以计算真正的经过时间,而与其他代码(或睡眠)花费的时间无关。

Roll that all together, and you can do something like this:将所有内容滚动在一起,您可以执行以下操作:

#include <chrono>
#include <iomanip>
#include <iostream>
#include <thread>

int main()
{
    using std::chrono::duration_cast;
    using std::chrono::milliseconds;
    using Clock = std::chrono::steady_clock;

    std::cout << std::setfill('0');

    auto tbegin = Clock::now();
    unsigned long elapsedMilli = -1U;
   
    do {
        Clock::duration elapsed = Clock::now() - tbegin;
        unsigned long ms = duration_cast<milliseconds>(elapsed).count();
        if (elapsedMilli == ms)
        {
            std::this_thread::sleep_until(tbegin + milliseconds(ms + 1));
            continue;
        }
        elapsedMilli = ms;

        // Build time
        unsigned int t_millisec = ms % 1000; ms /= 1000;
        unsigned int t_sec = ms % 60; ms /= 60;
        unsigned int t_min = ms % 60; ms /= 60;
        unsigned int t_hr = ms % 24; ms /= 24;
        //unsigned int t_days = ms;

        // Display time
        std::cout << "["
             << std::setw(2) << t_hr << ":"
             << std::setw(2) << t_min << ":"
             << std::setw(2) << t_sec << "."
             << std::setw(3) << t_millisec << "]\n";

    } while (elapsedMilli < 5000);
}

Live demo here: https://godbolt.org/z/fzGbvx1sa现场演示: https ://godbolt.org/z/fzGbvx1sa

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM