PHP利用多进程处理大文件

最近在做对账系统,有些渠道的对账单是按照机构号进行下载的,这就导致一个文件内可能又几十甚至上百万条的数据,如果用如果只用一个进程来跑的话,速度明显达不到预期,将会导致接下的汇总等脚本的执行。所以我想到了使用多进程的方式来加快对账单的处理速度。下面是我写的一个demo。

<?php
/**
 * Created by PhpStorm.
 * User: yanmi
 * Date: 2018/6/10
 * Time: 15:36
 */

namespace app\task\controller;


class ForkTest
{
    //测试将大文件分割,多进程同时处理,测试文件interface.syx.cnaccess.log 200多M 104W行
    public function index()
    {
        $st = microtime(true);
        shell_exec('split -l 20000 -d /tmp/interface.syx.cnaccess.log /tmp/billtest/prefix_name'); //将大文件切割成多个2W行数据的小文件
        $all = scandir('/tmp/billtest'); //扫描文件夹下的文件
        $len = ceil(count($all)/10); //一个进程分配10个文件
        for($i = 0; $i < $len; $i++){
            //在当前进程当前位置产生分支(子进程)。译注:fork是创建了一个子进程,父进程和子进程 都从fork的位置开始向下继续执行,
            $pid = pcntl_fork();

            if($pid == -1){ //创建子进程失败
                die();
            }else if($pid){ //如果$pid值>0,则表示这是在父进程
                pcntl_waitpid($pid, $status, WNOHANG);//等待子进程结束,如果没有子进程立即退出。非阻塞。用来防止子进程成为僵尸进程
                //pcntl_wait($status); 和上面的函数功能基本相同,但是它是阻塞的
            }else{ //这是在子进程中执行的代码
                $file_arr = array_slice($all, $i*10, 10);
                foreach ($file_arr as $item){
                    if($item === '.' || $item === '..'){ //跳过./和../
                        continue;
                    }
                    $num = $this->countLine($item);
                    echo "---- {$i} precess deal----: /tmp/billtest/{$item} has {$num} lines\r\n";
                }
                exit; //一定要注意退出子进程,子进程将会继续往下执行
            }
        }
        $et = microtime(true);
        $time = $et - $st;
        echo "process is over, spend {$time}S";
        exit;
    }

    /**
     * 统计文件数据行数
     * @param $file
     * @return int
     */
    public function countLine($file){
        $fp=fopen($file, "r");
        $i=0;
        while(!feof($fp)) {
            //每次读取2M
            if($data=fread($fp,1024*1024*2)){
                //计算读取到的行数
                $num=substr_count($data,"\n");
                $i+=$num;
            }
        }
        fclose($fp);
        return $i;
    }
}

书山有路勤为径 学海无涯苦作舟