php多进程ipc
由于php没有多线程机制,在一些cpu密集型任务时,只能起多进程操作,于是要考虑进程间通信等场景。
php已有方式包括:管道、消息队列、共享内存、socket,如下重点探究文件与共享内存
<?php
const SHM_VAR = 1;
const M = 20000;
const N = 100000;
const NUM = 10;
/**
* 1 文件
*/
function pipe()
{
// 申请锁资源
$sem_key = ftok( __FILE__, 'b' );
$sem_id = sem_get( $sem_key );
// 创建文件
$pipePath = "pipe1";
$file = fopen( $pipePath, 'w+');
fwrite( $file, 0);
for( $i = 0; $i < NUM; $i++ ){
$pid = pcntl_fork();
if( $pid < 0 ){
exit(-1);
}
if( $pid ==0 ) {
for ($j = M+$i; $j<=N; $j+=NUM) {
$mark =1;
for($n=2; $n<$j/2;$n++) {
if ($j % $n == 0) {
$mark = 0;
break;
}
}
if ($mark) {
sem_acquire($sem_id );
$file = fopen( $pipePath, 'r+');
$count= (int)fread( $file, 5);
$count++;
$file = fopen( $pipePath, 'w+');
fwrite($file, $count);
sem_release( $sem_id );
}
}
exit(-1);
}
}
for($n=0;$n<NUM;$n++)
{
pcntl_wait($status);
}
$file = fopen( $pipePath, 'r+');
echo (int)fread($file, 5) . PHP_EOL;
}
/**
* 2 共享内存
*/
function shareMemory()
{
// 申请锁资源
$sem_key = ftok( __FILE__, 'b' );
$sem_id = sem_get( $sem_key );
// 申请共享内存
$shm_key = ftok( __FILE__, 'm' );
$shm_id = shm_attach( $shm_key, 1024, 0666 );
//共享内存初始化
shm_put_var( $shm_id, SHM_VAR, 0 );
for( $i = 0; $i < NUM; $i++ ){
$pid = pcntl_fork();
if( $pid < 0 ){
exit(-1);
}
if( $pid ==0 ) {
for ($j = M+$i; $j<=N; $j+=NUM) {
$mark =1;
for($n=2; $n<$j/2;$n++) {
if ($j % $n == 0) {
$mark = 0;
break;
}
}
if ($mark) {
// 获取锁
sem_acquire($sem_id );
if( shm_has_var( $shm_id, SHM_VAR ) ){
$counter = shm_get_var( $shm_id, SHM_VAR );
$counter += 1;
shm_put_var( $shm_id, SHM_VAR, $counter );
}
sem_release( $sem_id );
}
}exit(-1);
}
}
for($n=0;$n<NUM;$n++)
{
pcntl_wait($status);
}
echo '最终结果'.shm_get_var( $shm_id, SHM_VAR ).PHP_EOL;
// 记得删除共享内存数据,删除共享内存是有顺序的,先remove后detach,顺序反过来php可能会报错
shm_remove( $shm_id );
shm_detach( $shm_id );
}
/**
* 3 消息队列
*/
function consumeQueue()
{
$filePath = __DIR__."/A.php";
echo $filePath.PHP_EOL;
$id = ftok($filePath,'m');
$msgQueue = msg_get_queue($id);
global $msgType;
$msgType = 1;
while (true) {
msg_receive($msgQueue,$msgType,$msgType,1024,$message);
echo $message;
}
}
function produceQueue()
{
$filePath = __DIR__."/A.php";
echo $filePath.PHP_EOL;
$id = ftok($filePath,'m');
$msgQueue = msg_get_queue($id);
while (!feof(STDIN)) {
$line = fread(STDIN, 1024);
//System V IPC key
msg_send($msgQueue, MSG_TYPE, $line);
}
}
/**
* 4 管道
*/
// 定义管道路径,与创建管道
function myPipe()
{
$pipe_path = 'test.pipe';
if(!file_exists($pipe_path)){
if(!posix_mkfifo($pipe_path,0664)){
exit("create pipe error!");
}
}
$pid = pcntl_fork();
if($pid == 0){
// 子进程,向管道写数据
$file = fopen($pipe_path,'w');
while (true){
fwrite($file,'hello world');
$rand = rand(1,3);
sleep($rand);
}
exit('child end!');
}else{
// 父进程,从管道读数据
$file = fopen($pipe_path,'r');
while (true){
$rel = fread($file,20);
echo "{$rel}\n";
$rand = rand(1,2);
sleep($rand);
}
}
}
/**
* 5 socket
*/
function udp()
{
}
function server1()
{
set_time_limit( 0 );
ob_implicit_flush();
$socket = socket_create( AF_INET, SOCK_DGRAM, SOL_UDP );
if ( $socket === false ) {
echo "socket_create() failed:reason:" . socket_strerror( socket_last_error() ) . "\n";
}
$ok = socket_bind( $socket, '10.33.150.172', 84 );
if ( $ok === false ) {
echo "socket_bind() failed:reason:" . socket_strerror( socket_last_error( $socket ) );
}
while ( true ) {
$from = "";
$port = 0;
socket_recvfrom( $socket, $buf,1024, 0, $from, $port );
echo $buf;
usleep( 1000 );
}
}
function client1()
{
$sock = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP);
while (!feof(STDIN)) {
$msg = fread(STDIN, 1024);
$len = strlen($msg);
socket_sendto($sock, $msg, $len, 0, '10.33.150.172', 84);
}
socket_close($sock);
}
/**
* tcp
*/
function server2()
{
set_time_limit( 0 );
ob_implicit_flush();
$socket = socket_create( AF_INET, SOCK_STREAM, SOL_TCP );
socket_bind( $socket, '10.33.150.172', 84 );
socket_listen($socket);
$acpt=socket_accept($socket);
echo "Acpt!\n";
while ( $acpt ) {
$words=fgets(STDIN);
socket_write($acpt,$words);
$hear=socket_read($acpt,1024);
echo $hear;
if("bye\r\n"==$hear){
socket_shutdown($acpt);
break;
}
usleep( 1000 );
}
socket_close($socket);
}
function client2()
{
set_time_limit( 0 );
ob_implicit_flush();
$socket = socket_create( AF_INET, SOCK_STREAM, SOL_TCP );
socket_bind( $socket, '10.33.150.172', 84 );
socket_listen($socket);
$acpt=socket_accept($socket);
echo "Acpt!\n";
while ( $acpt ) {
$words=fgets(STDIN);
socket_write($acpt,$words);
$hear=socket_read($acpt,1024);
echo $hear;
if("bye\r\n"==$hear){
socket_shutdown($acpt);
break;
}
usleep( 1000 );
}
socket_close($socket);
}
server2();
文件需要上锁保证进程同步性,同时会存在大量系统调用,读文件、写文件速度不如共享内存快;
共享内存,外加锁机制可是实现多个进程对同一块内存进行操作。