環境說明: 系統:Ubuntu14.04 (安裝教程包括CentOS6.5)
PHP版本:PHP⑸.5.10
swoole版本:1.7.7-stable
Github地址:https://github.com/LinkedDestiny/swoole-doc
在實際利用中,常常會遇到需要每隔1段時間重復做1件事,比如心跳檢測、定閱消息、http://www.jyygyx.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.jyygyx.com/db/常常是性能提升的瓶頸。而MySQL連接池我想大家都不陌生,這是1個很好的提升http://www.jyygyx.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