协程Mix PHP V2 基于 Swoole 4 的 PHP Stream Hook 协程技术开发,协程使用方式与 Golang 几乎一致,包括框架封装的协程池、连接池、命令行处理都大量参考了 Golang 的系统库风格。除了缺少 select case 外,Mix PHP 与 Golang 的协程几乎一致,框架还提供了连接池、协程池、命令行处理这些开箱即用的封装。xgo + Channelxgo 类似 Golang 的 go 关键字,可启动一个新的协程,Channel 等于 Golang 的 chan 类,负责在不同协程中传递数据。<?phpnamespace 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 + xdeferWaitGroup 与 Golang 的完全一致,xdefer 方法也等同于 Golang 的 defer 关键字。当并行执行且不需要返回结果时,可以使用 WaitGroup + xdefer,xdefer 即使在方法抛出异常时,仍然会执行,这样能避免一直处于阻塞状态。<?phpnamespace 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(); 方法。<?phpnamespace 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(); }}