所有文章

php多进程处理大任务

在写php脚本的过程中经常会遇到要并行处理大量数据的问题,比如说批量从数据库中处理几万行数据,调用第三方接口处理大数据等等,如果仅仅是循环去处理会导致非常低效,PHP本身是支持多进程的,如果让多个进程同时处理这部分数据就会让性能快很多。

在工作中遇到了一个这样的问题,把它抽象一下作为一个典型的例子记录,方便下次察看。

多进程生成csv文件的PHP脚本

代码见gist

简单的说明:

  1. 通过generateData方法生成测试数据,目标是把这部分测试数据写入到一个csv文件中
  2. 通过devideWork方法来分割任务,在初始化过程中定义了工作进程数量,生成每个工作进程的任务量也就是pageSize的值
  3. 在主进程中把csv头部写入文件
  4. 多进程的核心部分是runProcess方法,pcntl_fork生成子进程,让子进程执行写csv的操作writeCsvpcntl_wexitstatus回收子进程。

writeCsv是很慢的操作,但是pcntl_fork是很快的,如果一个进程一直等待着执行writeCsv就造成了低效,但是均分任务之后就飞快了。

什么任务可以多进程执行

自己简单总结一下可以分为:

  1. 任务可以明确分割,如果任务有很复杂的依赖关系,有严格的执行顺序要求,肯定没法并行
  2. 每一部分任务的结果可以很好的合并,在这里是追加到文件

对于PHP多进程模型的一些推测

  1. pcntl_fork生成的子进程是对父进程的深度拷贝,子进程拥有了父进程中的整个对象,每个对象都复制了一份data属性
  2. 子进程无法改变父进程中的变量,在writeCsv方法中子进程的$this->counter自增了,但是父进程中的$this->counter没有变化
  3. 子进程和父进程无法直接通信,必须借助类似文件句柄这样的东西才能共享数据,难怪在unix/linux的设计哲学中文件如此重要

几个文件相关的实用小命令

  1. 显示重复行

    sort FILE | uniq -cd
  2. 删除重复行

    awk '!seen[$0]++' filename
  3. 删除长度更短的行

    awk 'length($0)>3' filename