服务器cli模式下的定时器
有时候需要一部分后台业务异步的处理,比如处理redis队列啊,处理mysql统计啊,数据同步啊,这种长时间任务,但是又需要每段时间去看看的,发现linux cron最小只能支持每分钟的任务
分 时 天 月 星期
这颗粒度太大了,而我们实际业务往往需要几秒一次的查询或者每秒一次的业务,甚至有时候是毫秒级别的任务。
于是干脆写个后台一直运行的程序一直监控着。
最简单的方法使用 php while 死循环
<?php while (1) { }
发现这样CPU马上跑满了,这样消耗CPU太厉害也不行,然后给它休息一下也行
<?php while (1) { usleep(1000); }
每次1毫秒一次 这样其实CPU也消耗的不太高 百分之2-3左右吧
如果每1秒一次的话,几乎消耗的就不多了,百分之0.几
<?php while (1) { sleep(1); }
对于php开发者而言这也不错。
然后想想要不试试lua 发现lua 也有很多不同的方案。
首先可以尝试 while 死循环
while(1) do end
CPU都百分之130了,太可怕
然后加个休息 每秒休息一次
while(1) do os.execute("sleep " .. 1) end
发现这样就压根不占用CPU啊!不过然后发现这个时间是秒级别,换个毫秒级别的
local socket_now = require('socket') while(1) do socket_now.select(nil, nil, 0.001) end
这个就是1毫秒一次了 占用CPU 百分之3-4 也还不错。
当然完全也可以用swoole的那种定时器,不过感觉那还得搞swoole,得有学习成本,对很多公司的fpm模式而言,有时候只有几个业务是后台常驻需要弄个定时器的,这样也就足够了,简单好维护。
这里面的业务代码,可以使用redis或者文件缓存等方式,看看是不是有任务,简单迅速的查询是不是需要处理,需要就处理,给开始处理业务上一个锁,避免长时间没执行完,后面的循环又压上来了造成业务执行第二次,有锁了就不做处理等待sleep。
当然也有可能锁出现问题,一直锁住 导致业务一直无法继续,那就给它加一个过期时间,当锁自然过期后,最终还是能执行进来的,毕竟这程序在一直循环。
<?php while(1) { $check_flag = check_if_we_have_task_in_redis_or_cache(); if ($check_flag) { add_a_lock_for_flag(); handle_task(); } usleep(1000); }