现在已经有了时间了,下一步要做的就是让各个计算机知道这个时间,并不可能在每台电脑中放一个原子钟(或许在将来有可能),因此,由位于陕西省的国家授时中心,会把精确的时间用各种方式广播出去,聪明的你会想到,假设 A 在 t 时向 B 发送当前的 t,那么 B 在接受到 t 的时候已经是 t+a 时了,会有误差,这就需要 NTP 协议了。
假设有计算机 A(未同步时间),时间服务器 B,A 的时钟为 1:00:00 a.m.,B 的时钟为 2:00:00 a.m.,B 的信息传递到 A 要 1 秒,A 和 B 处理信息的时间均为 1 秒。
传输步骤:
A 发送信息给 B,带有离开时的时间戳(1:00:00 a.m. T1)。
B 接受信息后,加上到达时的时间戳(2:00:01 a.m. T2)。
B 传出此信息给 A,加上离开时的时间戳(2:00:02 a.m. T3)。
A 接收到信息后,加上到达的时间戳(1:00:03 T4)。
然后就可计算出如下信息:
信息来回一个周期的时延:
A 相对 B 的时间差:
$Offset=\frac{(T3-T4)+(T2-T1)}{2}$。
可知:
Delay=2 (s)
Offset=1 (h)
就可以同步啦。
## Part 3
回到这张图片:

可以发现 `real` 命令用时最长,比 `user` 返回的时间加 `sys` 返回的时间都要长,这是因为三个命令分别是这样的:
```
real:指的是从开始到结束所花费的时间。比如进程在等待I/O完成,这个阻塞时间也会被计算在内。
user:指的是进程在用户态(User Mode)所花费的时间,只统计本进程所使用的时间,注意是指多核。
sys:指的是进程在核心态(Kernel Mode)花费的CPU时间量,指的是内核中的系统调用所花费的时间,只统计本进程所使用的时间。
```
(以下用 real,sys,user 代指命令分别返回的结果)
通俗的来讲,real 命令包括了程序的运行时间和各种延迟时间,`user` 表示程序在 CPU 中自身执行的时间,`sys` 表示程序在调用系统资源使用的时间(比如创建进程啦等等)。
real 分为 CPU 执行时间和延迟时间,而 user 和 sys 合起来就是 CPU 执行时间,可知,在大多数情况下:
`real>user+sys`
当然,创建线程也需要时间,而 real 仅统计单线程时间,在多线程情况下,可能有
`real<user+sys`
因为此时线程可以并行执行。
由上可知,你真实感受到的时间是 real,所以这道题应该选 A,(我蒙对了)。通过观察也可见,此题中 `real>sys+user`,题目中也强调了是单核 CPU。
## Part 4
我的程序是选用哪种计时的呢?
当然是 `user+sys` 命令(不要妄想选最少的),这点还是很贴心的,至少已经把延迟去掉了。而我们的程序也都是单线程的(CCF 禁止调用线程相关函数),这可以看为是最贴近程序运行时间的。
在 c++ 中有 `clock` 函数,它返回的也是相当于 `user+sys`,有的同学会问了,那我在程序中 Sleep(1000),会多出这些时间吗?
答案是不会的,Sleep 函数是在内核层面上阻塞,影响的是 real 的时间,对于 `clock` 函数的计时并没有影响。
还有这样一个函数:`time`,它返回的是 1970 年 1 月 1 日至今所经历的时间(以秒为单位),如果用程序结束时的 `time` 减去程序开始时的 `time` 得到的相当于 `real` 的时间。
随机数也是利用了 `time` 作为时间种子,这在往期日报里有过讲述。
## Part 5
### 5-1
我如何给自己运行的程序计时
首先最简单的,在运行完一个程序后会有这样一行字:
圈起来的数字就是程序运行的时间(以秒为单位),不过这包含了键盘输入的时间,所以推荐使用文件输入输出。
> 指正:在运行程序后显示的运行时间是由ConsolePauser.exe提供的功能,在Dev-C++以外的IDE中可能没有,需要手动下载ConsolePauser.exe并且在程序运行时调用(ConsolePauser.exe 程序路径)
感谢 @Allenyou1126 提出
也可以在程序中使用 `clock` 函数或者是 `time` 函数计时。比如说,我想使用 `clock` 计算我的单循环程序运行时间,可以这样:
```cpp
#include<windows.h>
#include<bits/stdc++.h>
using namespace std;
int a[100000007];
int main(){
for(int i=1;i<=100000000;i++){
a[i]=i;//防止被编译器优化
}
cout<<"clock 计时: "<<clock()<<endl;
return 0;
}
```

在该程序中,有一个 $10^7$ 的循环,共用时 316ms,诶,这个程序没有输入啊,为什么下面显示的是 713.3ms 呢,clock 统计的仅仅是 CPU 时间,也就相当于 user+sys,所以嘛,会有这样的结果。
接下来是使用 time 计时的程序:
```cpp
#include<bits/stdc++.h>
using namespace std;
int a;
int main(){
int st=time(NULL);
for(int i=1;i<=1000000000;i++){
a++;//防止被编译器优化
}
int et=time(NULL);
cout<<"time 计时: "<<et-st<<endl;
return 0;
}
```

由于 time 以秒为单位,所以程序运行的时间需要长一点才能体现出来,否则在 1s 之内的话 time 计时都是 0。
不对啊,不是说程序结束时的时间减去程序开始时的时间就是 real 的时间吗?注意看,这里所获取到的 time 值是在程序里执行的,也就是说,这仅是两个 time 中间的 real 时间而已。
在 CCF 的规则中,有这样一句:
> 自测用时超过题目时限的5%,并由此提出的申诉,不予受理
那为什么有这 5% 呢,就是考虑到系统性能波动啊,延时误差啊等等。
## Part 6
题外话 千年虫事件
在 20 世纪 60 年代的时候,计算机还是非常的昂贵,存储成本也很高,开发人员们就习惯性的用六位数字来表示年份,如 1967.12.13 表示成 67/12/13 等,然而,他们没想到自己写的程序能用那么久,在 2000 即将到来时,人们发现程序识别不出是 2000 年 1 月 1 日还是 1900 年 1 月 1 日,因此,在两个世纪交接的时候,弄出了非常大的麻烦。
因此,养成良好的代码习惯,从我们做起吧(滑稽
## 注释及参考资料
[1]:[晶体振荡器](https://baike.baidu.com/item/%E6%99%B6%E4%BD%93%E6%8C%AF%E8%8D%A1%E5%99%A8/8742969)
参考资料:
[【网络干货】NTP时间同步技术详解](https://zhuanlan.zhihu.com/p/138339057)
[Linux系统-real/user/sys time](https://blog.csdn.net/baidu_35692628/article/details/77387827)
有不足之处欢迎指出