由于 PHP 具有"所思即所写"的强大优势, 使其在 Web 之外, 也被广泛用于后台脚本编写. 而且, 当你已经用 PHP 来开发 Web 应用时, 你显示不愿意再引入 Java 或者 Python 等语言, 再说, 这些语言相对 PHP 的强大优势, 显示太弱了.
不过, 用 PHP 来编写后台脚本, 也有一些劣势, 那便是 PHP 缺少并发模型. 例如, 当你用 HTTP 请求第三方服务, 而第三方每一个请求要处理 10 秒时, 这就需要你并发地发起请求. curl_multi 当然能处理, 但不通用, 而且对代码逻辑的改变太大, 需要从串行化改为批量化, 对思维干扰太大.
为此, PHP 提供了一套 Master-Workers 并发模型, 帮助你实现 PHP 的并发处理.
我们先来看看串行化的处理逻辑:
$jobs = Db::find(); foreach($jobs as $job){ process($job); // 执行时间 10 秒 }
如果是异步编程语言, 一般会这样改:
$jobs = Db::find(); foreach($jobs as $job){ async{ process($job); // 执行时间 10 秒 } // async 语句块立即返回, 可以理解为建立了新线程来处理 }
但是, 这是异步编程的重大错误, 因为没有并发控制. 所以, Golang 语言引入了 channel, 避免过多的并发, 这里就不讨论了.
而使用 iphp 的 Master-Workers 并发模型和工具, 则这样编写代码:
class MyMasterWorker extends MasterWorker { function master(){ $jobs = Db::find(); foreach($jobs as $job){ $this->add_job($job); } } function worker($job){ process($job); } } $m = new MyMasterWorker(); $m->set_num_workers(10); // 10 个并发 $m->run();
使用 iphp 的 Master-Workers 并发模型和工具, 你原来的代码几乎不用改变, 仅仅是将代码在空间上移动了一下位置.
关于实现原理, 简单介绍一下. iphp 采用了 pcnt_fork() 实现多进程并发, 并通过 socket 来实现进程间通信(任务分发).
下载地址: https://github.com/ideawu/iphp
完整示例: https://github.com/ideawu/iphp/blob/master/mw/test.php