环境说明: 系统:Ubuntu14.04 (安装教程包括CentOS6.5)
PHP版本:PHP⑸.5.10
swoole版本:1.7.7-stable
Github地址:https://github.com/LinkedDestiny/swoole-doc
在实际利用中,常常会遇到需要每隔1段时间重复做1件事,比如心跳检测、定阅消息、http://www.wfuyu.com/db/备份等工作。通常,我们会借助PHP的time()和相干函数自己实现1个定时器,或使用crontab工具来实现。但是,自定义的定时器容易出错,而使用crontab则需要编写额外的脚本文件,不管是迁移还是调试都比较麻烦。
因此,Swoole提供了1个内置的Timer定时器功能,通过函数addtimer便可在Swoole中添加1个定时器,该定时器会在建立以后,依照预先设定好的时间间隔,每到对应的时间就会调用1次回调函数onTimer通知Server。
简单示例以下:
可以看到,在onWorkerStart回调函数中,通过addtimer添加了3个定时器,时间间隔分别为500、1000、1500。而在onTimer回调中,正好通过间隔的不同来辨别不同的定时器回调,从而履行不同的操作。
需要注意的是,在上述示例中,当1000ms的定时器被触发时,500ms的定时器一样会被触发,但是不能保证会在1000ms定时器前触发回是后触发,因此需要注意,定时器中的操作不能依赖其他定时器的履行结果。
点此查看完全示例
(PS:在Swoole⑴.7.7版本,新提供了1个after函数, 这个功能的用法会在以后的教程中给出。)
上文提到过,使用Timer定时器功能可以实现发送心跳包的功能。事实上,Swoole已内置了心跳检测功能,能自动close掉长时间没有数据来往的连接。而开启心跳检测功能,只需要设置heartbeat_check_interval和heartbeat_idle_time便可。以下:
其中heartbeat_idle_time的默许值是heartbeat_check_interval的两倍。 在设置这两个选项后,swoole会在内部启动1个线程,每隔heartbeat_check_interval秒后遍历1次全部连接,检查最近1次发送数据的时间和当前时间的差,如果这个差值大于heartbeat_idle_time,则会强迫关闭这个连接,并通过回调onClose通知Server进程。 点此查看完全示例 小技能: 结合之前的Timer功能,如果我们想保持连接,就设置1个略小于如果这个差值大于heartbeat_idle_time的定时器,在定时器内向所有连接发送1个心跳包。如果收到心跳回应,则判断连接正常,如果没有收到,则关闭这个连接或再次尝试发送。
上1章中我简单讲授了如何开启和使用Task功能。这1节,我将提供1个Task的高级用法。
在PHP中,访问MySQLhttp://www.wfuyu.com/db/常常是性能提升的瓶颈。而MySQL连接池我想大家都不陌生,这是1个很好的提升http://www.wfuyu.com/db/访问性能的方式。传统的MySQL连接池,是预先申请1定数量的连接,每个新的要求都会占用其中1个连接,要求结束后再将连接放回池中,如果所有连接都被占用,新来的连接则会进入等待状态。
知道了MySQL连接池的实现原理,那我们来看如何使用Swoole实现1个连接池。
首先,Swoole允许开启1定量的Task Worker进程,我们可让每一个进程都具有1个MySQL连接,并保持这个连接,这样,我们就创建了1个连接池。
其次,设置swoole的dispatch_mode为抢占模式(主进程会根据Worker的忙闲状态选择投递,只会投递给处于闲置状态的Worker)。这样,每一个task都会被投递给闲置的Task
Worker。这样,我们保证了每一个新的task都会被闲置的Task Worker处理,如果全部Task Worker都被占用,则会进入等待队列。
下面直接上关键代码:
首先,在每一个Task Worker进程中,创建1个MySQL连接。这里我选用了PDO扩大。
其次,在需要的时候,通过task函数投递1个任务(也就是发起1次SQL要求)
最后,在onTask回调中,根据要求过来的SQL语句和相应的参数,发起1次MySQL要求,并将获得到的结果通过send发送给客户端(或通过return返回给Worker进程)。而且,这样的1次MySQL要求还不会阻塞Worker进程,Worker进程可以继续处理其他的逻辑。
可以看到,简单10几行代码,就实现了1个高效的异步MySQL连接池。
通过测试,单个客户端1共发起1W次select要求,共耗时9s;
1W次insert要求,共耗时21s。
(客户端会在每次收到前1个要求的结果后才会发起下1次要求,而不是并发)。
点此查看完全服务端代码
点此查看完全客户端代码
下章预告:Swoole多端口监听、热重启和Timer进阶:简单crontab