在写php脚本的过程中经常会遇到要并行处理大量数据的问题,比如说批量从数据库中处理几万行数据,调用第三方接口处理大数据等等,如果仅仅是循环去处理会导致非常低效,PHP本身是支持多进程的,如果让多个进程同时处理这部分数据就会让性能快很多。
在工作中遇到了一个这样的问题,把它抽象一下作为一个典型的例子记录,方便下次察看。
多进程生成csv文件的PHP脚本
代码见gist
简单的说明:
- 通过
generateData
方法生成测试数据,目标是把这部分测试数据写入到一个csv文件中 - 通过
devideWork
方法来分割任务,在初始化过程中定义了工作进程数量,生成每个工作进程的任务量也就是pageSize的值 - 在主进程中把csv头部写入文件
- 多进程的核心部分是
runProcess
方法,pcntl_fork
生成子进程,让子进程执行写csv的操作writeCsv
,pcntl_wexitstatus
回收子进程。
writeCsv
是很慢的操作,但是pcntl_fork
是很快的,如果一个进程一直等待着执行writeCsv
就造成了低效,但是均分任务之后就飞快了。
什么任务可以多进程执行
自己简单总结一下可以分为:
- 任务可以明确分割,如果任务有很复杂的依赖关系,有严格的执行顺序要求,肯定没法并行
- 每一部分任务的结果可以很好的合并,在这里是追加到文件
对于PHP多进程模型的一些推测
pcntl_fork
生成的子进程是对父进程的深度拷贝,子进程拥有了父进程中的整个对象,每个对象都复制了一份data
属性- 子进程无法改变父进程中的变量,在
writeCsv
方法中子进程的$this->counter
自增了,但是父进程中的$this->counter
没有变化 - 子进程和父进程无法直接通信,必须借助类似文件句柄这样的东西才能共享数据,难怪在unix/linux的设计哲学中文件如此重要
几个文件相关的实用小命令
-
显示重复行
sort FILE | uniq -cd
-
删除重复行
awk '!seen[$0]++' filename
-
删除长度更短的行
awk 'length($0)>3' filename