php中strtotime函数性能分析
作者:hebedich 发布时间:2023-11-22 13:21:05
最近在做一个游戏数据统计后台,最基础的功能是通过分析注册登录日志来展示用户数据。在公司内部测试,用户量很少,所以就没有发现什么性能问题。但是这两天一起放到真实的测试环境,用户量噌噌地就涌进来了,从下午开始,在线人数的统计开始卡,几秒钟才返回数据;注册人数的查询速度还行。到了晚上,在线人数的统计基本上就加载超时打不开了。虽然不知他们游戏端那边什么BUG,玩家那边登录经常出问题,导致在线人数和注册人数并不是很多。但是就这一点数据量我这边查询的速度也不行,这就很尴尬了。
现在他们那边在查游戏的BUG,我这边也在看统计后台的代码到底性能出在哪里。首先说明一下,我统计用的数据是从库,他们游戏用的是主库,再说我这边管理员人数就几个,不可能会影响到游戏服的性能问题。
今天项目组长把数据库都导过来到公司内的服务器。我拷了一份到本机,看看统计平台的性能问题出在哪里。然后却发现,居然连注册统计都非常卡,服务器上是两秒左右返回,本机要二十几秒,还经常超时(PHP的默认配置是30秒超时);在线统计的就不用说了肯定打不开。看了一下数据库,当天的注册记录也就 3500 条左右(有假数据),每五分钟统计一次,一天就是统计 288 次。当然这里肯定不是循环查询数据库288次,那样会被骂死的吧。
统计时间段内的注册数,逻辑也非常简单,就是每个时间段遍历一次数据,比较时间大小,符合就+1。但是为什么这么简单的逻辑,也就一百万次循环,怎么会跑出了足足半分钟的时间那么久呢?
关键问题就出在于 时间比较这里了,我们都知道,时间戳是比较时间大小的一个比较科学的方法,而数据库里记录的时间一般都是以 YYYY-mm-dd HH:ii:ss 的形式,PHP里有strtotime的函数转换成时间戳。然而在288个for * 3500个foreach 的加持之后,这里的执行时间长达半分钟。
$nowDayDT = strtotime( date('Y-m-d') );
$__startT = microtime(TRUE);
for($i=0; $i<$allTime; $i += $gapTime){
$count = 0;
//用于数据比较的
$startDT = $nowDayDT+$i;
$endDT = $nowDayDT+$i+$gapTime;
//用于显示的
$xAxis1 = date('H:i', $nowDayDT+$i);
$xAxis2 = date('H:i', $nowDayDT+$i+$gapTime);
foreach($rawData as $line){
$time = strtotime($line['log_dt']);
if( $startDT<=$time && $time<$endDT ){
$count ++;
}
}
$resArr[] = [
'date'=>$xAxis1.'~'.$xAxis2,
'number'=>$count
];
}
echo microtime(TRUE)-$__startT;
那这样的话,基本上是没办法再用这个strtotime的函数的了,那还有什么办法比较时间大小呢?答案很简单粗暴,PHP里面可以直接比较两个日期时间字符串!所以改过后的代码如下。然后现在的运行时间大概是 0.3秒
$__startT = microtime(TRUE);
for($i=0; $i<$allTime; $i += $gapTime){
$count = 0;
//用于数据比较的
$startDT = date('Y-m-d H:i:s', $nowDayDT+$i);
$endDT = date('Y-m-d H:i:s', $nowDayDT+$i+$gapTime);
//用于显示的
$xAxis1 = date('H:i', $nowDayDT+$i);
$xAxis2 = date('H:i', $nowDayDT+$i+$gapTime);
foreach($rawData as $line){
$time = $line['log_dt'];
if( $startDT<=$time && $time<$endDT ){
$count ++;
}
}
$resArr[] = [
'date'=>$xAxis1.'~'.$xAxis2,
'number'=>$count
];
}
echo microtime(TRUE)-$__startT;
遍历再优化
大家可能发现一个问题,for 里面嵌套一个 foreach,这性能有点担忧,其中里面的 foreach 有必要完全遍历吗?其实是不必的。只要查SQL数据的时候,按时间排序排出来。优化后的时间比较算法如下:
for{ ...
foreach($rawData as $line){
$time = $line['log_dt'];//strtotime($line['log_dt']);
//优化算法计算
if($time<$startDT) continue; //小于开始时间则跳过
if($time>=$endDT) break; //大于结束时间则结束
$count ++; //否则为符合条件
//原始的算法
// if( $startDT<=$time && $time<$endDT ){
// $count ++;
// }
}
...}
这里巧用了 continue 和 break 关键字,用于跳过一次循环和结束整个循环。这次的话,一天中刚开始的时间统计中,后面很大一部分数据的都可以直接跳过。最后总遍历时间缩短为约0.12秒 。
总结,在大型的数据处理中,应该尽量避免在遍历中进行数据的转换,避免用一些原理复杂的函数。如strtotime
猜你喜欢
- 本文实例讲述了Python通过递归遍历出集合中所有元素的方法。分享给大家供大家参考。具体实现方法如下:''''
- fileinput模块可以遍历文本文件的所有行.它的工作方式和readlines很类似,不同点在于,它不是将全部的行读到列表中而是创建了一个
- 本文实例讲述了PHP读取txt文本文件并分页显示的方法。分享给大家供大家参考。具体实现方法如下:<?php &n
- 前言在本文中,我们将介绍一些常见的分布并通过Python 代码进行可视化以直观地显示它们。概率和统计知识是数据科学和机器学习的核心;&nbs
- 一、缓存目的1、减小过载2、避免重复计算3、提高系统性能二、如何进行缓存三、缓存类型四、缓存粒度分类五、缓存的设置与使用示例一:CACHES
- pip安装的话,找到自己安装python的路径,在安装路径下会有一个文件夹,比如我的安装路径是c盘我是默认安装路径,在里面有一个python
- 使用场景先来观察以下代码:abstract class base { //do sth}class aClass extends
- 1. RequestDispatcher.forward()在服务器端起作用,当使用forward()时,Servlet engine传递H
- 写在之前这几天的阅读量蜜汁低,是什么原因我也没搞清楚,如果你们觉得我哪里写的有问题,或者是哪里不好,欢迎后台或者微信告知我,先行谢过。昨天的
- 今天在老师工作室做项目的时候,突然看到一个页面用了2种不同的传值类型,突然有了兴趣,想弄明白本质的区别,虽然以前用的知道2种的用法,但是还是
- vue.js在生成相关js和css文件的时候,名称是通过HASH的方式进行生成的,但是每次生成的文件基本都是一样的,那么浏览器就会缓存这些文
- python序列类型包括哪三种python序列类型包括:列表、元组、字典列表:有序可变序列创建:userlist = [1,2,3,4,5,
- 问题描述在消费rabbitMQ队列时, 每次进入回调函数内需要进行一些比较耗时的操作;操作完成后给rabbitMQ server发送ack信
- 本文实例为大家分享了微信小程序无滑动效果的tab点击切换的具体代码,供大家参考,具体内容如下<!--pages/dingdan/din
- Pycharm要激活至2099年,首先必须要先找到这个东西:JetbrainsCrack-2.6.10-release-enc.jar,我上
- Python获取当前时间_获取格式化时间:Python获取当前时间:使用 time.time( ) 获取到距离1970年1月1日的秒数(浮点
- 1.cv2.threshold()参数说明cv2.threshold(src, thresh, maxval, type[, dst]) &
- 前言APScheduler是基于Quartz的一个Python定时任务框架。提供了基于日期、固定时间间隔以及crontab类型的任务,并且可
- console.log,作为一个前端开发者,可能每天都会用它来分析调试,但这个简单函数背后不简单那一面,你未必知道……基础首先,简单科普这个
- 因为系统的一个Bug,导致数据库表中出现重复数据,需要做的是删除重复数据且只保留最新的一条数据。具体场景是这样的有张订单关联额外费用表,而且