不知道大家还记得在学校的时候体育测试时老师带的秒表吗?当枪声想起时,我们开始跑步,这时秒表启动,当我们跑过终点后,老师会按下按扭记录我们的成绩,这就是一个典型的定时器的应用。今天我们要学习的内容其实就是和这个体育测验的秒表类似的一个功能扩展,它就是 PHP 的 HRTime 扩展。

时钟节拍

首先我们要了解一下什么叫做系统的时钟节拍。当 Linux 系统启动之后,会同时启动一个时钟节拍器,以纳秒为单位进行计时,而我们的 HRTime 扩展的真实名称是 高精度时间 扩展。也就是说,它正是基于操作系统的时钟节拍器,能够以纳秒为单位进行计时。

1秒=1000毫秒=1000000微妙=1000000000纳秒,这是秒、毫秒、微秒和纳秒的关系,看出来它的精度有多高了吧。1秒等于10亿纳秒,这样我们就可以获得一个非常精确的时间间隔计数。

HRTime 扩展直接在 PECL 进行下载安装就可以了,和其他的普通扩展没有什么区别。

获取系统时钟节拍信息 Ticks

我们先来看看如何获取操作系统的时钟节拍,也就是这个 Ticks 。关于它的内容在学习操作系统的时候相信已经有不少的同学接触过了,这里我们看看使用 HRTime 扩展如何获取。

print_r(hrtime());
// Array
// (
// [0] => 3758
// [1] => 407409171
// ) echo hrtime(true), PHP_EOL;
// 3758407428932

hrtime() 这个函数在 PHP7 之后已经集成在默认 PHP 环境中了。它不需要 HRTime 扩展就可以使用。这个函数在没有参数的情况下返回的是一个数组,第 0 项是系统启动到现在的秒数,第 1 项就是对应的纳秒计数。如果给它的参数设置一个 true 的话,它将直接返回将秒和纳秒拼接起来的实际纳秒时间戳。

echo HRTime\PerformanceCounter::getFrequency(), PHP_EOL; // 1000000000
echo HRTime\PerformanceCounter::getTicks(), PHP_EOL; // 3758428256236
echo HRTime\PerformanceCounter::getTicksSince(1212), PHP_EOL; // 3758428257494 $a = HRTime\PerformanceCounter::getTicks();
echo HRTime\PerformanceCounter::getTicksSince($a), PHP_EOL; // 412

接下来的这三个函数就是 HRTime 扩展中的 PerformanceCounter 对象的静态函数了。PerformanceCounter 对象的意思是性能计数器,getFrequency() 表示的是计时器频率(以滴答Ticks/秒为单位),可以看出,它返回的就是纳秒单位,也就是 10亿 。getTicks() 返回的是当前的时钟节拍时间,可以看出它和 hrtime(true) 函数的结果是一样的,都是返回的系统启动后的时钟节拍时间。getTicksSince() 方法则是根据指定的纳秒数返回时间间隔,类似于 date_diff() 的感觉,其实就像我们的 time() - time() 这样的操作。通过这个方法就可以获得一段代码两次运行的时间间隔,而且是以纳秒为单位哦。

定时器功能

接下来就是我们文章的重点内容了,也就是定时器功能的实现。上面已经说过,使用 getTickSince() 其实也能做到监控一段代码的运行时间间隔,不过下面将学习到的内容将更加强大。

$c = new HRTime\StopWatch;

$c->start();
for ($i = 0; $i < 1024*1024; $i++);
echo 'isRunning: ', $c->isRunning(), PHP_EOL; // isRunning: 1
$c->stop(); echo 'Time NS: ', $c->getLastElapsedTime(HRTime\Unit::NANOSECOND), PHP_EOL;
echo 'Time US: ', $c->getLastElapsedTime(HRTime\Unit::MICROSECOND), PHP_EOL;
echo 'Time MS: ', $c->getLastElapsedTime(HRTime\Unit::MILLISECOND), PHP_EOL;
echo 'Time S: ', $c->getLastElapsedTime(HRTime\Unit::SECOND), PHP_EOL;
// Time NS: 6929888
// Time US: 6929.888
// Time MS: 6.929888
// Time S: 0.006929888 echo 'Ticks: ',$c->getLastElapsedTicks(), PHP_EOL;
// Ticks: 6929888 echo 'isRunning: ',$c->isRunning(), PHP_EOL;
//

我们需要实例化一个 StopWatch 对象,然后调用它的 start() 方法,这样一个定时器就启动了。StopWatch 的英文涵义本身就是定时器的意思,所以这个对象是专门为定时器的操作所服务的。通过 isRunning() 方法我们可以判断当前定时器是否运行,其实就是判断当前是否是在一个 start() 方法之后,如果不在 start() 和 stop() 范围中,那么它将返回 false 。在测试代码中,我们运行一个 1024*1024 的空循环,然后再使用 stop() 方法结束定时器。

从代码中可以看出,getLastElapsedTime() 就是获得我们上面的那个 start() 到 stop() 之间的代码运行耗时的时间间隔信息,它的参数可以指定为秒、毫秒、微秒、纳秒。本身这个方法的意思就是获取获取最后一个间隔的运行时间。getLastElapsedTicks() 则是获得最后一次间隔的时钟节拍信息。既然有【最后一次】这四个字,那么也就说明这个对象是可以多次调用的来分段计时的。并且,它还是可以将多段不同的计时进行汇总,获得全部的时间间隔信息的。

// 不在计时范围内
for ($i = 0; $i < 1024*1024; $i++); $c->start();
for ($i = 0; $i < 1024*1024; $i++);
$c->stop(); echo 'Time NS: ', $c->getLastElapsedTime(HRTime\Unit::NANOSECOND), PHP_EOL;
echo 'Time US: ', $c->getLastElapsedTime(HRTime\Unit::MICROSECOND), PHP_EOL;
echo 'Time MS: ', $c->getLastElapsedTime(HRTime\Unit::MILLISECOND), PHP_EOL;
echo 'Time S: ', $c->getLastElapsedTime(HRTime\Unit::SECOND), PHP_EOL;
// Time NS: 7154010
// Time US: 7154.01
// Time MS: 7.15401
// Time S: 0.00715401 echo 'All Time NS: ', $c->getElapsedTime(HRTime\Unit::NANOSECOND), PHP_EOL;
echo 'All Time US: ', $c->getElapsedTime(HRTime\Unit::MICROSECOND), PHP_EOL;
echo 'All Time MS: ', $c->getElapsedTime(HRTime\Unit::MILLISECOND), PHP_EOL;
echo 'All Time S: ', $c->getElapsedTime(HRTime\Unit::SECOND), PHP_EOL;
// All Time NS: 14083898
// All Time US: 14083.898
// All Time MS: 14.083898
// All Time S: 0.014083898 echo 'All Ticks: ', $c->getElapsedTicks(), PHP_EOL;
// All Ticks: 14083898

在这段代码中,我们在两段计时测试代码中插入了一个循环测试代码,它不会计入到计时数据中。接着,我们重新 start() 开始一个新的计时,在最后,我们通过 getElapsedTime() 和 getElapsedTicks() 两个方法获得总的计时时间,可以看出上面的 6929888 加上这次的 7154010 结果正好是 14083898 。中间的那一段没有在定时器中的循环代码没有计入到总的计时时间中。

总结

是不是很有意思,它的作用真的和我们的体育老师所用的那个秒表一模一样,老师们的秒表也都是可以按多次记录第1名到最后1名的全部跑步成绩,并且最后还有一个总的时间,而在代码中我们也是完全相似的操作。这个扩展对于精细的性能调试非常有用,而且也能够针对一些需要这种高精度时间差的业务进行相关的开发。

测试代码:

https://github.com/zhangyue0503/dev-blog/blob/master/php/202010/source/3.学习PHP中的高精度计时器HRTime扩展.php

参考文档:

https://www.php.net/manual/zh/book.hrtime.php

https://www.cnblogs.com/chezxiaoqiang/archive/2012/03/23/2674386.html

关注公众号:【硬核项目经理】获取最新文章

添加微信/QQ好友:【xiaoyuezigonggong/149844827】免费得PHP、项目管理学习资料

知乎、公众号、抖音、头条搜索【硬核项目经理】

B站ID:482780532

学习PHP中的高精度计时器HRTime扩展的更多相关文章

  1. 学习PHP中好玩的Gmagick图像操作扩展的使用

    在 PHP 的图像处理领域,要说最出名的 GD 库为什么好,那就是因为它不需要额外安装的别的什么图像处理工具,而且是随 PHP 源码一起发布的,只需要在安装 PHP 的时候添加上编译参数就可以了. G ...

  2. 学习PHP中的iconv扩展相关函数

    想必 iconv 这个扩展的相关函数大家多少都接触过,做为 PHP 的默认扩展它已经存在了很久,也是我们在操作字符编码时经常会使用的函数.不过除了 iconv() 这个函数外,你还知道它的其它函数吗? ...

  3. 学习PHP中Fileinfo扩展的使用

    今天来学习的这个扩展其实现在也已经是标配的一个扩展了,为什么呢?因为 Laravel 框架在安装的时候它就是必须的一个扩展,没有打开它的话,连 Laravel 框架都是无法使用的. Fileinfo ...

  4. PHP中非常好玩的Calendar扩展学习

    为什么说这个 Calendar 扩展很好玩呢?因为你基本用不到它!这个扩展是一套关于日期历法的扩展,但是对于我们来说,它没有农历的相关操作,所以对于我们中国人来说这个扩展并没有什么实际的作用.不过这并 ...

  5. 学习PHP中的任意精度扩展函数

    今天来学习的是关于数学方面的第一个扩展.对于数学操作来说,无非就是那些各种各样的数学运算,当然,整个程序软件的开发过程中,数学运算也是最基础最根本的东西之一.不管你是学得什么专业,到最后基本上都会要学 ...

  6. Direct3D 10学习笔记(二)——计时器

    本篇将简单整理Direct3D 10的计时器实现,具体内容参照< Introduction to 3D Game Programming with DirectX 10>(中文版有汤毅翻译 ...

  7. C#下利用高精度计时器进行计时操作

    简介 精确的时间计量方法在某些应用程序中是非常重要的.常用的 Windows API 方法 GetTickCount() 返回系统启动后经过的毫秒数.另一方面,GetTickCount() 函数仅有 ...

  8. Android学习开发中如何保持API的兼容

    Android学习开发中如何保持API的兼容: 1,采用良好的设计思路 在设计过程中,如果能按照下面的方式来进行设计,会让这个API生命更长久 面向用例的设计,收集用户建议,把自己模拟成用户,保证AP ...

  9. 如何理解并学习javascript中的面向对象(OOP) [转]

    如果你想让你的javascript代码变得更加优美,性能更加卓越.或者,你想像jQuery的作者一样,写出属于自己优秀的类库(哪怕是基于 jquery的插件).那么,你请务必要学习javascript ...

随机推荐

  1. Golang语言系列-07-函数

    函数 函数的基本概念 package main import ( "fmt" ) // 函数 // 函数存在的意义:函数能够让代码结构更加清晰,更简洁,能够让代码复用 // 函数是 ...

  2. MySQL-02-体系结构

    MySQL体系结构 c/s模型介绍 连接MySQL # TCP/IP方式(远程.本地) mysql -uroot -pAlnk123 -h 10.0.0.51 -P3306 # Socket方式(仅本 ...

  3. 说说XXE漏洞那些事

    想不起来写点啥了,又是摸鱼的一天,看了一些红队大佬们整理的资料,非常精彩,于是一个咸鱼翻身先选了一些简单的小点来写一写个人的感想(后续会继续更新其他内容) 不能说写的是技术分享,因为师傅们的文章珠玉在 ...

  4. Azkaban入门(启动一个Simple Example)

    Azkaban简介 azkaban是一个开源的任务调度系统 Azkaban是一套简单的任务调度服务,整体包括三部分webserver.dbserver.executorserver. 开发语言为Jav ...

  5. HashTable原理和底层实现

    1. 概述 上次讨论了HashMap的结构,原理和实现,本文来对Map家族的另外一个常用集合HashTable进行介绍.HashTable和HashMap两种集合非常相似,经常被各种面试官问到两者的区 ...

  6. 【小技巧】排名前 16 的 Java 工具类!

    转自java技术栈: https://mp.weixin.qq.com/s?__biz=MzI3ODcxMzQzMw==&mid=2247485460&idx=1&sn=cef ...

  7. springmvc学习日志二

    一.当接受的参数为日期类型时 1.建立jsp页面,向Controller类传入参数 1.1当传入的参数为单个时 <body> <form action="user/toDa ...

  8. 解决方案-问题001:物理机、虚机等等Linux操作系统/usr/bin目录权限误操作,导致无法切换root

    导语:平常运维人员会误操作一些目录权限,导致一些问题,那么如何恢复呢? 问题:物理机.虚机等等Linux操作系统/usr/bin目录权限误操作,导致无法切换root? 实验环境: ip地址 是否目录正 ...

  9. Linux基于Docker的Redis主从复制、哨兵模式搭建

    本教程基于CentOS7,开始本教程前,请确保您的Linux系统已安装Docker. 1.使用docker下载redis镜像 docker pull redis 安装完成后,使用docker imag ...

  10. Python+mirai开发QQ机器人起步教程(2021.9.9测试有效)

    参考:开发 mirai QQ机器人起步教程_叹之-CSDN博客_mirai python 本篇文章参考了以上博客,并对其中的失效内容和版本匹配问题进行了补充修改,实测能够成功运行.部分步骤的运行截图见 ...