以实例全面讲解PHP中多进程编程的相关函数的使用
|
PHP有一组进程控制函数(编译时需要–enable-pcntl与posix扩展),使得php能实现跟c一样的创建子进程、使用exec函数执行程序、处理信号等功能。 // 必须加载扩展if (!function_exists("pcntl_fork")) { die("pcntl extention is must !"); } //总进程的数量 $totals = 3; // 执行的脚本数量 $cmdArr = array(); // 执行的脚本数量的数组 for ($i = 0; $i < $totals; $i++) { $cmdArr[] = array("path" => DIR . "/run.php",'pid' =>$i,'total' =>$totals); } /*
) pcntl_signal(SIGCHLD,SIG_IGN); //如果父进程不关心子进程什么时候结束,子进程结束后,内核会回收。 使用PHP真正的多进程运行模式,适用于数据采集、邮件群发、数据源更新、tcp服务器等环节。 PHP有一组进程控制函数(编译时需要 –enable-pcntl与posix扩展),使得php能在*nix系统中实现跟c一样的创建子进程、使用exec函数执行程序、处理信号等功能。 PCNTL使用ticks来作为信号处理机制(signal handle callback mechanism),可以最小程度地降低处理异步事件时的负载。何谓ticks?Tick 是一个在代码段中解释器每执行 N 条低级语句就会发生的事件,这个代码段需要通过declare来指定。 常用的PCNTL函数 1. pcntl_alarm ( int $seconds )设置一个$seconds秒后发送SIGALRM信号的计数器2. pcntl_signal ( int $signo,callback $handler [,bool $restart_syscalls ] )为$signo设置一个处理该信号的回调函数。下面是一个隔5秒发送一个SIGALRM信号,并由signal_handler函数获取,然后打印一个“Caught SIGALRM”的例子:function signal_handler($signal) { print "Caught SIGALRMn"; pcntl_alarm(5); } pcntl_signal(SIGALRM,"signal_handler",true); for(;;) { ?> 3. pcntl_exec ( string $path [,array $args [,array $envs ]] )在当前的进程空间中执行指定程序,类似于c中的exec族函数。所谓当前空间,即载入指定程序的代码覆盖掉当前进程的空间,执行完该程序进程即结束。$arg = array($cmd,$option,$dir); pcntl_exec($pathtobin,$arg); 4. pcntl_fork ( void )为当前进程创建一个子进程,并且先运行父进程,返回的是子进程的PID,肯定大于零。在父进程的代码中可以用 pcntl_wait(&$status)暂停父进程知道他的子进程有返回值。注意:父进程的阻塞同时会阻塞子进程。但是父进程的结束不影响子进程的运行。 父进程运行完了会接着运行子进程,这时子进程会从执行pcntl_fork()的那条语句开始执行(包括此函数),但是此时它返回的是零(代表这是一个子进程)。在子进程的代码块中最好有exit语句,即执行完子进程后立即就结束。否则它会又重头开始执行这个脚本的某些部分。注意两点:
5. pcntl_wait ( int &$status [,int $options ] )阻塞当前进程,只到当前进程的一个子进程退出或者收到一个结束当前进程的信号。使用$status返回子进程的状态码,并可以指定第二个参数来说明是否以阻塞状态调用: 阻塞方式调用的,函数返回值为子进程的pid,如果没有子进程返回值为-1; 非阻塞方式调用,函数还可以在有子进程在运行但没有结束的子进程时返回0。6. pcntl_waitpid ( int $pid,int &$status [,int $options ] )功能同pcntl_wait,区别为waitpid为等待指定pid的子进程。当pid为-1时pcntl_waitpid与pcntl_wait 一样。在pcntl_wait和pcntl_waitpid两个函数中的$status中存了子进程的状态信息,这个参数可以用于 pcntl_wifexited、pcntl_wifstopped、pcntl_wifsignaled、pcntl_wexitstatus、 pcntl_wtermsig、pcntl_wstopsig、pcntl_waitpid这些函数。 例如:子进程在输出child process等字样之后sleep了2秒才结束,而父进程阻塞着直到子进程退出之后才继续运行。 7. pcntl_getpriority ([ int $pid [,int $process_identifier ]] )取得进程的优先级,即nice值,默认为0,在我的测试环境的linux中(CentOS release 5.2 (Final)),优先级为-20到19,-20为优先级最高,19为最低。(手册中为-20到20)。8. pcntl_setpriority ( int $priority [,int $pid [,int $process_identifier ]] )设置进程的优先级。9. posix_kill可以给进程发送信号10. pcntl_singal用来设置信号的回调函数当父进程退出时,子进程如何得知父进程的退出 当父进程退出时,子进程一般可以通过下面这两个比较简单的方法得知父进程已经退出这个消息: 当父进程退出时,会有一个INIT进程来领养这个子进程。这个INIT进程的进程号为1,所以子进程可以通过使用getppid()来取得当前父进程的pid。如果返回的是1,表明父进程已经变为INIT进程,则原进程已经推出。 使用kill函数,向原有的父进程发送空信号(kill(pid,0))。使用这个方法对某个进程的存在性进行检查,而不会真的发送信号。所以,如果这个函数返回-1表示父进程已经退出。 除了上面的这两个方法外,还有一些实现上比较复杂的方法,比如建立管道或socket来进行时时的监控等等。 PHP多进程采集数据的例子 class Signfork{ /**
/**
if(is_array($arg)){ if($i>1000) exit('Too many spawns!'); /**
/**
|
