上一篇的源码看得十分无趣,官方文档跟黑心棉一样渣。

  这一篇讲讲windows操作系统上的时间戳实现,由于类的声明,方法解释上一篇都贴过了,所以这次直接上对应版本的代码。

  windows与mac很不一样,实现了一个新的Clock类来管理时间,如下。

// We implement time using the high-resolution timers so that we can get
// timeouts which are smaller than 10-15ms. To avoid any drift, we
// periodically resync the internal clock to the system clock.
class Clock final {
public:
Clock() : initial_ticks_(GetSystemTicks()), initial_time_(GetSystemTime()) {} Time Now() { /* */ } Time NowFromSystemTime() { /* */ } private:
static TimeTicks GetSystemTicks() { /* */ } static Time GetSystemTime() { /* */ } TimeTicks initial_ticks_;
Time initial_time_;
Mutex mutex_;
};

  从注释和方法名可以看出,windows完全用这个新类代替了老的Time、TimeTicks,因为这个方法拥有更好的性能,这个类同时会周期性的与系统时间同步数据。

  下面正式开始。

  先从Now方法看起,看windows系统是如何获取本地的时间戳。

DEFINE_LAZY_LEAKY_OBJECT_GETTER(Clock, GetClock)

#define DEFINE_LAZY_LEAKY_OBJECT_GETTER(T, FunctionName, ...) \
T* FunctionName() { \
static ::v8::base::LeakyObject<T> object{__VA_ARGS__}; \
return object.get(); \
} Time Time::Now() { return GetClock()->Now(); }

  这个方法的定义也不一般,直接用了一个特殊宏,宏就不展开了,简单说就是懒加载,调用的时候会分配空间生成一个Clock类,初始化完后第二次调用就直接返回了,当成一个单例来理解。

  直接看宏的返回类型,刚好是上面的Clock,该类只有一个无参构造函数,初始化两个时间戳属性。

  先看后那个,也就是系统时间的时间戳。

static Time GetSystemTime() {
FILETIME ft;
::GetSystemTimeAsFileTime(&ft);
return Time::FromFiletime(ft);
}

  这里的FILETIME和GetSystemTimeAsFileTime都是windowsAPI,可以获取当前系统的日期和时间,但是返回值很奇怪。

typedef struct _FILETIME {
DWORD dwLowDateTime;
DWORD dwHighDateTime;
} FILETIME, *PFILETIME, *LPFILETIME;

Contains a 64-bit value representing the number of 100-nanosecond intervals since January 1, 1601 (UTC).

  这是结构体的声明与解释,High、Low分别代表时间的高位与地位,而那个方法就是配合这个使用的。

  可以从上面看到,这个API返回的时间竟然是从1601年1月1日开始算的,不知道那一年发生了什么。

  下面写一个测试代码。

int main()
{
FILETIME ft;
LARGE_INTEGER t;
::GetSystemTimeAsFileTime(&ft);
t.LowPart = ft.dwLowDateTime;
t.HighPart = ft.dwHighDateTime;
cout << t.QuadPart << endl;
}

  得到的输出为132034487665022709,由于单位是100纳秒,所以这个数字乘以100的,然后换算一下。

  由于基准是1601年,而Date是从1970年开始算,所以年份上差了369年,刚好是2019,很合理。

  来看看V8的处理。

// Time between windows epoch and standard epoch.
static const int64_t kTimeToEpochInMicroseconds = int64_t{}; Time Time::FromFiletime(FILETIME ft) {
// 特殊情况处理
if (ft.dwLowDateTime == && ft.dwHighDateTime == ) {
return Time();
}
if (ft.dwLowDateTime == std::numeric_limits<DWORD>::max() &&
ft.dwHighDateTime == std::numeric_limits<DWORD>::max()) {
return Max();
}
// 换算
int64_t us = (static_cast<uint64_t>(ft.dwLowDateTime) +
(static_cast<uint64_t>(ft.dwHighDateTime) << )) / ;
return Time(us - kTimeToEpochInMicroseconds);
}

  前面的特殊情况看看就行了,主要是换算这一步,就是简单的将高低位的数值拼到了一起,除以10之后,单位从100纳秒变成了微秒。

  最后的计算,也是为了平衡标准的时间戳和windows时间戳两者的差异,如下。

  为什么不是1970 - 1601 = 369年整呢?因为中间有闰年,很合理。

  最后得到微秒单位的标准时间戳,将该数值赋到类的属性上。

  回到最初的Now方法,初始化完后,会调用Clock自身的Now方法获取最终的时间戳,如下。

Time Now() {
// 一个误差临界值
const TimeDelta kMaxElapsedTime = TimeDelta::FromMinutes(); // 我目前不想解析所有关于锁的东西
MutexGuard lock_guard(&mutex_); // 再次获取当前的硬件时间戳与本地时间戳
TimeTicks ticks = GetSystemTicks();
Time time = GetSystemTime(); // 这里进行误差修正
TimeDelta elapsed = ticks - initial_ticks_;
// 1.当前时间小于初始化时间 可参考上一篇中类方法的注释(the system might adjust its clock...)
// 2.硬件时间戳的时间差超过临界值 这种情况基本可以认定初始化的时间完全不可信了
if (time < initial_time_ || elapsed > kMaxElapsedTime) {
initial_ticks_ = ticks;
initial_time_ = time;
return time;
} return initial_time_ + elapsed;
}

  虽然在构造函数中获取了时间戳,但是V8考虑到由于函数调用、系统修正等原因导致的误差(比如第一次初始化),再次进行了修正,具体操作和原因可以直接看注释,最后返回的时间戳是计算获得的理论本地时间戳加上硬件时间戳差值。

  至于NewFromSystemTime就比较简单了,在mac中这两个方法是一个,在windows里如下。

Time NowFromSystemTime() {
MutexGuard lock_guard(&mutex_);
// 更新两个时间戳
initial_ticks_ = GetSystemTicks();
initial_time_ = GetSystemTime();
// 直接返回最新获得的时间戳
return initial_time_;
}

  不计算任何东西,直接返回系统API的时间戳,可以配合注释来理解这两个方法。  

  尴尬了,没想到V8在Time阶段把两个时间戳全用上了。稍微看了一下TimeTicks的实现,发现还有点意思,所以这一篇先这样了,太长了写的累。

深入V8引擎-Time核心方法之win篇(1)的更多相关文章

  1. 深入V8引擎-Time核心方法之win篇(2)

    这一篇讲windows系统下TimeTicks的实现. 对于tick,V8写了相当长的一段discussion来讨论windows系统上计数的三种实现方法以及各自的优劣,注释在time.cc的572行 ...

  2. 深入V8引擎-Time核心方法之mac篇

    由于底层逻辑实现不同操作系统区别很大,所以干脆分篇来说. 主要讲一下Time.TimeTicks两个类里面对于时间戳的实现,其余的运算符重载.边缘工具方法就不看了,先是Time. Time 类本身的说 ...

  3. 浅谈Chrome V8引擎中的垃圾回收机制

    垃圾回收器 JavaScript的垃圾回收器 JavaScript使用垃圾回收机制来自动管理内存.垃圾回收是一把双刃剑,其好处是可以大幅简化程序的内存管理代码,降低程序员的负担,减少因 长时间运转而带 ...

  4. 浅谈V8引擎中的垃圾回收机制

    最近在看<深入浅出nodejs>关于V8垃圾回收机制的章节,转自:http://blog.segmentfault.com/skyinlayer/1190000000440270 这篇文章 ...

  5. 深入出不来nodejs源码-V8引擎初探

    原本打算是把node源码看得差不多了再去深入V8的,但是这两者基本上没办法分开讲. 与express是基于node的封装不同,node是基于V8的一个应用,源码内容已经渗透到V8层面,因此这章简述一下 ...

  6. Chrome V8引擎系列随笔 (1):Math.Random()函数概览

    先让大家来看一幅图,这幅图是V8引擎4.7版本和4.9版本Math.Random()函数的值的分布图,我可以这么理解 .从下图中,也许你会认为这是个二维码?其实这幅图告诉我们一个道理,第二张图的点的分 ...

  7. (译)V8引擎介绍

    V8是什么? V8是谷歌在德国研发中心开发的一个JavaScript引擎.开源并且用C++实现.可以用于运行于客户端和服务端的Javascript程序. V8设计的初衷是为了提高浏览器上JavaScr ...

  8. V8引擎嵌入指南

    如果已读过V8编程入门那你已经熟悉了如句柄(handle).作用域(scope)和上下文(context)之类的关键概念,以及如何将V8引擎作为一个独立的虚拟机来使用.本文将进一步讨论这些概念,并介绍 ...

  9. EF5+MVC4系列(9) Razor视图引擎的核心原理;@符号的使用;输出html的转义

    一:Razor视图引擎的核心原理 Razor是ASP.NET MVC 3中新加入的技术,以作为ASPX引擎的一个新的替代项 ,他是一个视图引擎 他的核心原理,就是当读取到 @符号的时候,就认为这是开始 ...

随机推荐

  1. 笔记-python-build-in-types

    笔记-python-build-in-types 注:文档内容来源为Python 3.6.5 documentation 1.      built-in types 1.1.    真值测试 所有对 ...

  2. JVM——Java类加载机制总结

    )解析:解析阶段是把虚拟机中常量池的符号引用替换为直接引用的过程. 2.3 初始化 类初始化时类加载的最后一步,前面除了加载阶段用户可以通过自定义类加载器参与以外,其余都是虚拟机主导和控制.到了初始化 ...

  3. v-model 的修饰符

    1..trim 自动过滤输入内容最开始 和 最后的 空格,中间的会保留一个空格,多的会被过滤掉 2..lazy 一般情况下,在input的 v-model是一直在同步 输入的内容与显示的内容,不过再添 ...

  4. Redis实现之数据库(三)

    过期键删除策略 在Redis实现之数据库(二)一小节中,我们知道了数据库键的过期时间都保存在过期字典中,又知道了如果根据过期时间去判断一个键是否过期,现在剩下的问题是:如果一个键过期了,那么它什么时候 ...

  5. NopCommerce 导航菜单HTML静态处理以提高性能

    因网站要快速上线,有时候NopCommerce性能问题一直是困扰我们的最大因素,查找出来需要优化的部分代码进行修改重构是方法之一,我等非主流优化方式只为快速提高程序整体性能. 我以导航菜单为例,列出我 ...

  6. 相当牛X的java版星际游戏

    分享一款牛人用java写的经典游戏,目录结构如下: 虽然只能算一个Demo,但是用到了很多Java基础技术和算法: Java2D,双缓冲,A星寻路,粒子系统,动画效果,处理图片,Swing ui ,U ...

  7. 线段树&树状数组模板

    树状数组: #include <bits/stdc++.h> using namespace std; ; struct binit { int a[MAXN], n; void modi ...

  8. Android版本对应的API号

    Android版本 API 级别 1.5 API 3 1.6 API 4 2.1 API 7 2.2 API 8 2.3.3 API 10 3.0 API 11 3.1 API 12 3.2 API ...

  9. 禁用jQuery chosen的选择下拉菜单

    想法是启用被勾掉之后,左侧下拉框禁用.这是chosen()的 disabled之后需要更新一下.就这样,还有别的方法的话请分享,O(∩_∩)O哈哈~

  10. windows server 2012 下IIS8.5关于“ 配置错误 不能在此路径中使用此配置节”的解决办法

    服务器升级为windows server 2012 r2后,发布在新装的IIS8.5上的网站不能访问,页面显示“500 - 内部服务器错误.” 在服务器上调试后,提示的错误信息为: 配置错误 不能在此 ...