碎碎碎碎屁

从str2time开始的优化

by on 4月.07, 2013, under ,

线上有个perl的脚本,准实时(1分钟cron着)的跑着,一般一跑要1分多钟。之前初看还以为是sql设计差、脚本变量都是全局等等问题,后来想想不行,得用数据说话,于是找到了传说中的nytprof。安装据说要先装下JSON::Any,再装Devel::NYTProf;用的时候perl -d:NYTProf ./a.pl,再nytprofhtml nytprof.out下,好了现在只要w3m nytprof/index.html就能看到详细了。

不看不知道,一看吓一跳,最前面耗时最长的居然都是Date::Parse、Time::Local,而main、DBI这些原以为会慢的差前面两个Date、Time一个数量级啊。那今天就把目光放在Date::Parse里,仔细看了脚本,其实就是用到了str2time,把形如”2013-04-07 22:22:22″的转化为那个秒数。我们这个脚本大概执行一次会用到50多万次的str2time。

网上翻了翻说是Date::Parse慢,于是换了个Time::ParseDate,测试用例如下:
#1.pl
use Date::Parse;
my $start = "2013-04-08 02:00:00";
my $end = "2013-04-08 03:00:00";
for (my $i = 0; $i < 100000; $i++)
{ print str2time($start),"\n",str2time($end),"\n";}
#2.pl
use Time::ParseDate;
my $start = "2013-04-08 02:00:00";
my $end = "2013-04-08 03:00:00";
for (my $i = 0; $i < 100000; $i++)
{ print parsedate($start),"\n",parsedate($end),"\n";}

time比较出来的时间是从原来的13秒变成9秒,稍有提高。

期间多次strace发现经常会访问/etc/localtime,怀疑是模块里不论何时都要去算下现在时间引起的,遂决定直接用timelocal这个最基本的命令传入年月日时分秒来计算。
#3.pl
use Time::Local;
sub new() {
$_ = @_[0];
my( $Y,$M,$D,$h,$m,$s ) = /(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/;
return timelocal($s,$m,$h,$D,$M-1,$Y);
}
my $start = "2013-04-08 02:00:00";
my $end = "2013-04-08 03:00:00";
for (my $i = 0; $i < 100000; $i++)
{ print &new($start),"\n",&new($end),"\n";}

于2.pl的耗时比较,从9秒降到6秒多。

strace里还是能看到访问/etc/localtime,在Time::Local里看到还有timegm,试试
> return timelocal($s,$m,$h,$D,$M-1,$Y);
< return timegm($s,$m,$h,$D,$M-1,$Y)-28800;

由于并不牵涉时区,遂直接写死在里面。瞬间,从6秒多降到2秒内,和最开始比已经下降了一个数量级了。所以那,调用次数高的函数啊一定要好好调教下~

把这个提给原脚本owner后发现,原脚本只是为了比较两个时间string转后的大小。他直接改成
> return timegm($s,$m,$h,$D,$M-1,$Y)-28800;
< return ($Y*366*24*3600 + $M*31*24*3600 + $D*24*3600 + $h*3600 + $m*60 + $s);

来进行比较。时间差不多从2秒内变为1秒内。

然后洗澡时候忽然想起别人说过笑话,数据库存时间直接用string存20130407222222,于是测试这样比大小。
sub new() {
$a = @_[0];
$a =~ tr/ \-://d ;
return $a;
}
my $start = "2013-04-08 02:00:00";
my $end = "2013-04-08 03:00:00";
for (my $i = 0; $i < 1000000; $i++)
{ if (&new($start) < &new($end)){print 1};}

测试用例上提高一个数量级跑,上一种7秒多,这一种2秒多。
#p.s.用=~ s/\-|\s*|\://g;代替=~ tr/ \-://d;会比上一段所说的还要慢
也就是说,最开始13秒的,现在已经变成0.2秒了,所以那,优化逻辑也很重要~

改了之后load下降

Leave a Comment :, more...

dabr及类dabr对id升位的更新

by on 11月.07, 2010, under

前两天twitter官方把自己的消息id长度从14位升到15位,dabr,奶瓶腿等类dabr均受影响,具体状况就是id变成了“9.07755871273E+14”这类神奇值了。今天腿叔 @kcome 说dabr r358没问题,于是折腾了下把自用奶瓶腿都修改了下,同时感谢 @yaofur 同学的指点。要修改两处,都在common/twitter.php里。参考这里或者接着看我说

  1. function theme_status($status)的下一行增加

    if($status->id_str) $status->id = $status->id_str;

  2. function twitter_standard_timeline($feed, $source)的下两行,也就switch前面增加
    if (is_array($feed)) {
    	foreach($feed as $key => $status) {
    		if($status->id_str) {
    		$feed[$key]->id = $status->id_str;
    		}
    		if($status->in_reply_to_status_id_str) {
    		$feed[$key]->in_reply_to_status_id = $status->in_reply_to_status_id_str;
    		}
    		if($status->retweeted_status->id_str) {
    		$feed[$key]->retweeted_status->id = $status->retweeted_status->id_str;
    		}
    	}
    }

20101112新增如下修改,修复了search页面继续科学计数法的问题。也是修改common/twitter.php,也可以参考这儿

  1. 在function twitter_search里(约1100行)修改

    $tl = twitter_standard_timeline($tl, ‘search’);

    $tl = twitter_standard_timeline($tl->results, ‘search’);

  2. 在function twitter_standard_timeline下的case ‘search’下(约1400行修改

    foreach ($feed->results as $status) {

    foreach ($feed as $status) {

Leave a Comment :, , , , , , more...