Mix PHP V2 基於 Swoole 4 的 PHP Stream Hook 協程技術開發,協程使用方式與 Golang 幾乎一致,包括框架封裝的協程池、鏈接池、命令行處理都大量參考了 Golang 的系統庫風格。php
除了缺乏 select case 外,Mix PHP 與 Golang 的協程幾乎一致,框架還提供了鏈接池、協程池、命令行處理這些開箱即用的封裝。git
xgo 相似 Golang 的 go 關鍵字,可啓動一個新的協程,Channel 等於 Golang 的 chan 類,負責在不一樣協程中傳遞數據。github
<?php
namespace Console\Commands;
use Mix\Core\Coroutine\Channel;
use Mix\Core\Event;
/**
* Class CoroutineCommand
* @package Console\Commands
* @author liu,jian <coder.keda@gmail.com>
*/
class CoroutineCommand
{
/**
* 主函數
*/
public function main()
{
xgo(function () {
$time = time();
$chan = new Channel();
for ($i = 0; $i < 2; $i++) {
xgo([$this, 'foo'], $chan);
}
for ($i = 0; $i < 2; $i++) {
$result = $chan->pop();
}
println('Total time: ' . (time() - $time));
});
Event::wait();
}
/**
* 查詢數據
* @param Channel $chan
*/
public function foo(Channel $chan)
{
$db = app()->dbPool->getConnection();
$result = $db->createCommand('select sleep(5)')->queryAll();
$db->release(); // 不手動釋放的鏈接不會歸還鏈接池,會在析構時丟棄
$chan->push($result);
}
}
複製代碼
執行結果爲 5s,說明是並行執行的。編程
WaitGroup 與 Golang 的徹底一致,xdefer 方法也等同於 Golang 的 defer 關鍵字。bash
當並行執行且不須要返回結果時,能夠使用 WaitGroup + xdefer,xdefer 即便在方法拋出異常時,仍然會執行,這樣能避免一直處於阻塞狀態。app
<?php
namespace Console\Commands;
use Mix\Concurrent\Sync\WaitGroup;
use Mix\Core\Event;
/**
* Class WaitGroupCommand
* @package Console\Commands
* @author liu,jian <coder.keda@gmail.com>
*/
class WaitGroupCommand
{
/**
* 主函數
*/
public function main()
{
xgo(function () {
$wg = WaitGroup::new();
for ($i = 0; $i < 2; $i++) {
$wg->add(1);
xgo([$this, 'foo'], $wg);
}
$wg->wait();
println('All done!');
});
Event::wait();
}
/**
* 查詢數據
* @param WaitGroup $wg
*/
public function foo(WaitGroup $wg)
{
xdefer(function () use ($wg) {
$wg->done();
});
println('work');
throw new \RuntimeException('ERROR');
}
}
複製代碼
即使拋出了 RuntimeException 異常,仍然能執行到 println('All done!');
,沒有致使 wg 內的 chan 一直處於阻塞狀態。框架
異步編程中,定時器的使用很是頻繁。異步
Timer::new()
可得到一個實例after
方法可設置一次性定時tick
方法可設置持續定時$timer->clear();
方法。<?php
namespace Console\Commands;
use Mix\Core\Event;
use Mix\Core\Timer;
/**
* Class TimerCommand
* @package Console\Commands
* @author liu,jian <coder.keda@gmail.com>
*/
class TimerCommand
{
/**
* 主函數
*/
public function main()
{
// 一次性定時
Timer::new()->after(1000, function () {
println(time());
});
// 持續定時
$timer = new Timer();
$timer->tick(1000, function () {
println(time());
});
// 中止定時
Timer::new()->after(10000, function () use ($timer) {
$timer->clear();
});
Event::wait();
}
}
複製代碼