稳定时钟与系统时钟之间的区别?
我试图通过查看数据的时间戳来查看我的数据是否存在 120 秒,因此我有以下代码:
I am trying to see whether my data is 120 second old or not by looking at the timestamp of the data so I have below code:
uint64_t now = duration_cast<milliseconds>(steady_clock::now().time_since_epoch()).count();
bool is_old = (120 * 1000 < (now - data_holder->getTimestamp()));
在上面的代码中 data_holder->getTimestamp()
是 uint64_t ,它以毫秒为单位返回时间戳.
In the above code data_holder->getTimestamp()
is uint64_t which returns timestamp in milliseconds.
现在当我打印出 now
变量值时,我看到了这个 10011360
并且当我打印出 data_holder->getTimestamp()
值时这是 1437520382241
所以现在和数据持有者时间戳的差异应该是负数吧?为什么它会像下面的日志中显示的那样积极?
Now when I print out now
variable value, I see this 10011360
and when I print out data_holder->getTimestamp()
value which is 1437520382241
so the difference of now and data holder timestamp should be negative right? Why it is coming as positive as shown in the below logs?
2015-07-21 16:13:02,530 WARN 0x7f35312d1700 data_check - now value: 10011360 , data holder timestamp: 1437520382241 , difference: 18446742636199180735
我上面的代码看起来对吗?从上面的数据持有者时间戳来看,它看起来不是 120 秒的旧数据,所以我觉得我的代码有问题?因为如果我将该数据持有者的时间戳转换为实际时间(使用纪元转换器),然后将其与如上所示的日志时间进行比较,它几乎是相同的.
Does my above code looks right? And from the above data holder timestamp, it doesn't look to be 120 second old data right so I feel something is wrong in my code? Since if I convert that data holder timestamp to actual time (using epoch converter) and then compare it with logs time as shown above it is almost same.
我正在使用 steady_clock
如上所示.我需要在这里使用 system_clock
吗?steady_clock
与 system_clock
在外行术语中有什么区别.我在 Ubuntu 14.04 机器上运行此代码.
I am using steady_clock
as shown above. Do I need to use system_clock
here? What is the difference between steady_clock
vs system_clock
in layman terms. I am running this code on Ubuntu 14.04 box.
推荐答案
反序答题:
steady_clock
和 system_clock
在外行有什么区别条款.
What is the difference between
steady_clock
vssystem_clock
in layman terms.
如果你手里拿着一个system_clock
,你可以称它为watch,它会告诉你现在几点了.
If you're holding a system_clock
in your hand, you would call it a watch, and it would tell you what time it is.
如果你手里拿着一个steady_clock
,你会称它为秒表,它会告诉你某人跑了一圈的速度,但它会不告诉你现在几点了.
If you're holding a steady_clock
in your hand, you would call it a stopwatch, and it would tell you how fast someone ran a lap, but it would not tell you what time it is.
如果需要,您可以使用手表为某人跑一圈计时.但是,如果您的手表(如我的手表)定期与另一台机器(如 Boulder CO 的原子钟)通信以将自身校正到当前时间,则它可能会在计时该圈时出现小错误.秒表不会犯这个错误,但它也不能告诉你正确的当前时间.
If you had to, you could time someone running a lap with your watch. But if your watch (like mine) periodically talked to another machine (such as the atomic clock in Boulder CO) to correct itself to the current time, it might make minor mistakes in timing that lap. The stopwatch won't make that mistake, but it also can't tell you what the correct current time is.
我上面的代码看起来对吗?
Does my above code look right?
没有.即使它给了你合理的答案,我也不会说它是正确的.不要难过,这是很多人使用 <chrono>
库时犯的初学者错误.
No. And even if it gave you reasonable answers, I would not say it is right. Don't feel bad, this is a beginner mistake that lots of people make with the <chrono>
library.
<chrono>
库我遵循一个简单的规则.该规则实际上并不完全正确(因此它是一个准则).但它已经足够接近纠正,成为几乎总是遵循的准则:
There is a simple rule I follow with the <chrono>
library. The rule is actually not completely correct (thus it is a guideline). But it is close enough to correct to be a guideline that is nearly always followed:
不要使用 count()
.
还有一个推论:
不要使用 time_since_epoch()
.
<chrono>
库是围绕类型安全 系统设计的,旨在保护您免受单位转换错误的影响.如果您不小心尝试了不安全的转换,则会在编译时捕获错误(而不是运行时错误).
The <chrono>
library is designed around a type-safe system meant to protect you from units conversions mistakes. If you accidentally attempt an unsafe conversion, the error is caught at compile time (as opposed to it being a run time error).
成员函数 count()
和 time_since_epoch()
是这种类型安全系统的逃生舱"......仅在紧急情况下使用.当(例如)委员会没有为您提供完成 <chrono>
类型的工作所需的所有工具(例如 I/O)时,就会出现此类紧急情况,或者例如需要通过整数与其他一些计时 API 交互.
The member functions count()
and time_since_epoch()
are "escape hatches" out of this type-safe system ... to be used only in cases of emergency. Such emergencies arise when (for example) the committee neglects to give you all the tools you need to get the job done (such as I/O) for the <chrono>
types, or such as the need to interface with some other timing API via integers.
查看您和其他人的代码以使用 count()
和 time_since_epoch()
并仔细检查这些函数的每次使用:是否有任何如何重写代码以消除它们的使用?
Review your code and other's for use of count()
and time_since_epoch()
and scrutinize each use of these functions: Is there any way the code could be rewritten to eliminate their use?
查看代码的第一行:
uint64_t now = duration_cast<milliseconds>(steady_clock::now().time_since_epoch()).count();
now
是一个 time_point
(来自 steady_clock
).它的单位是 毫秒
,但目前我不相信这些单位很重要.重要的是 now
是从 steady_clock
检索到的 time_point
:
now
is a time_point
(from steady_clock
). It units are milliseconds
, but at this time I'm not convinced that the units are important. What is important is that now
is a time_point
retrieved from steady_clock
:
auto now = steady_clock::now();
你的第二行更复杂:
bool is_old = (120 * 1000 < (now - data_holder->getTimestamp()));
让我们从data_holder->getTimestamp()
开始:如果你可以修改getTimestamp()
,你应该修改它返回一个time_point
而不是 uint64_t
.为此,您必须知道正确的单位(您所做的 - 毫秒),并且您必须知道正确的纪元.纪元是衡量您的毫秒数的时间点.
Let's start with data_holder->getTimestamp()
: If you can modify getTimestamp()
, you should modify it to return a time_point
instead of a uint64_t
. To do so, you will have to know the correct units (which you do -- milliseconds), and you will have to know the correct epoch. The epoch is the time point against which your milliseconds are measured from.
在这种情况下,1437520382241ms 大约是 45.6 年.假设这是最近的时间戳,45.6 年前非常接近 1970-01-01.事实证明,system_clock()
的每个实现都使用 1970-01-01 作为它的纪元(尽管每个实现从这个纪元计算不同的单位).
In this case 1437520382241ms is about 45.6 years. Assuming this is a recent time stamp, 45.6 years ago was very close to 1970-01-01. As it turns out, every implementation of system_clock()
uses 1970-01-01 as its epoch (though each implementation counts different units from this epoch).
所以要么修改 getTimestamp()
以返回 time_point
,或者将 getTimestamp()
的返回值用 time_point
:
So either modify getTimestamp()
to return a time_point<system_clock, milliseconds>
, or wrap the return of getTimestamp()
with time_point<system_clock, milliseconds>
:
auto dh_ts = system_clock::time_point{milliseconds{data_holder->getTimestamp()}};
现在你的第二行是:
bool is_old = (120 * 1000 < (now - dh_ts));
另一个很好的指南:
如果您在 <chrono>
代码中看到转换因子,则说明您做错了.<chrono>
lives 为你 进行转换.
If you see conversion factors in your
<chrono>
code, you're doing it wrong.<chrono>
lives for doing the conversions for you.
bool is_old = (minutes{2} < (now - dh_ts));
下一步是风格化的,但现在你的代码很简单,如果你喜欢的话,可以去掉多余的括号:
This next step is stylistic, but now your code is simple enough to get rid of your excess parentheses if that is something that appeals to you:
bool is_old = minutes{2} < now - dh_ts;
如果您能够修改 getTimestamp()
以返回类型安全的值,则此代码也可能如下所示:
If you were able to modify the getTimestamp()
to return a type-safe value this code could also look like:
bool is_old = minutes{2} < now - data_holder->getTimestamp();
唉,不管怎样,这仍然无法编译!错误消息应说明 now
和 dh_ts
之间没有有效的 operator-()
.
Alas, either way, this still does not compile! The error message should state something along the lines that that there is no valid operator-()
between now
and dh_ts
.
这是一种类型安全系统,可帮助您避免运行时错误!
This is the type-safety system coming in to save you from run time errors!
问题是 system_clock
中的 time_point
s 不能从 steady_clock
中的 time_point
s 中减去(因为两者的时代不同).所以你必须切换到:
The problem is that time_point
s from system_clock
can't be subtracted from time_point
s from steady_clock
(because the two have different epochs). So you have to switch to:
auto now = system_clock::now();
把它们放在一起:
#include <chrono>
#include <cstdint>
#include <memory>
struct DataHolder
{
std::chrono::system_clock::time_point
getTimestamp()
{
using namespace std::chrono;
return system_clock::time_point{milliseconds{1437520382241}};
}
};
int
main()
{
using namespace std;
using namespace std::chrono;
auto data_holder = std::unique_ptr<DataHolder>(new DataHolder);
auto now = system_clock::now();
bool is_old = minutes{2} < now - data_holder->getTimestamp();
}
在 C++14 中,最后一行可以更简洁一些:
And in C++14 that last line can be made a little more concise:
bool is_old = 2min < now - data_holder->getTimestamp();
总结:
- 拒绝使用
count()
(I/O 除外). - 拒绝使用
time_since_epoch()
(I/O 除外). - 拒绝使用转换系数(例如 1000).
- 与它争论,直到它编译.?/li>
- Refuse to use
count()
(except for I/O). - Refuse to use
time_since_epoch()
(except for I/O). - Refuse to use conversion factors (such as 1000).
- Argue with it until it compiles.
如果您在上述四点上取得成功,您很可能不会遇到任何运行时错误(但您将获得公平份额的编译时错误).
If you succeed in the above four points, you will most likely not experience any run time errors (but you will get your fair share of compile time errors).
相关文章