프로세스는 특정 데이터 수집에 대해 독립적인 기능을 가진 프로그램의 실행 활동입니다. 즉, 시스템이 여러 CPU를 스케줄링할 때 프로그램의 기본 단위입니다. 프로세스는 대부분의 언어에 생소한 개념이 아니며 "세계 최고의 언어인 PHP"는 확실히 예외입니다.
PHP에서의 프로세스는 확장 기능의 형태로 완성됩니다. 이러한 확장을 통해 프로세스에서 일련의 작업을 쉽게 완료할 수 있습니다.
pcntl 확장: 메인 프로세스 확장, 완료 프로세스는 대기 작업에서 생성됩니다.
posix 확장: 프로세스 ID 가져오기, 프로세스 종료 등과 같은 POSIX 호환 시스템에 대한 전체 공통 API를 제공합니다.
sysvmsg 확장: system v 모드에서 프로세스 간 통신을 위한 메시지 대기열을 구현합니다.
sysvsem 확장: 시스템 v 세마포어를 구현합니다.
sysvshm 확장: 시스템 v 모드에서 공유 메모리를 구현합니다.
sockets 확장: 소켓 통신을 구현합니다.
이 확장 기능은 Linux/Mac에서만 사용할 수 있으며 Windows에서는 지원되지 않습니다. 마지막으로 PHP 버전은 5.5 이상을 권장합니다.
간단한 PHP 다중 프로세스 예에는 하나의 하위 프로세스와 하나의 상위 프로세스가 있습니다. 자식 프로세스는 5번의 출력을 내고 프로그램을 종료합니다.
$parentPid = posix_getpid(); echo "parent progress pid:{$parentPid}\n"; $childList = array(); $pid = pcntl_fork(); if ( $pid == -1) { // 创建失败 exit("fork progress error!\n"); } else if ($pid == 0) { // 子进程执行程序 $pid = posix_getpid(); $repeatNum = 5; for ( $i = 1; $i <= $repeatNum; $i++) { echo "({$pid})child progress is running! {$i} \n"; $rand = rand(1,3); sleep($rand); } exit("({$pid})child progress end!\n"); } else { // 父进程执行程序 $childList[$pid] = 1; } // 等待子进程结束 pcntl_wait($status); echo "({$parentPid})main progress end!";
완벽해요. 마침내 하위 프로세스와 상위 프로세스를 만들었습니다. 끝났나요? 아니요, 각 프로세스는 서로 독립적이고 교차점이 없으며 사용 범위가 심각하게 제한됩니다. 무엇을 해야 할까요?
4. IPC(프로세스 간 통신)
Linux에서 일반적으로 프로세스 통신 방법에는 메시지 큐, 세마포어, 공유 메모리, 신호, 파이프 및 소켓이 포함됩니다.
1. 메시지 큐
메시지 큐는 메모리에 저장되는 큐입니다. 다음 코드는 3개의 생산자 하위 프로세스와 2개의 소비자 하위 프로세스를 생성합니다. 이 5개 프로세스는 메시지 큐를 통해 통신합니다.
$parentPid = posix_getpid(); echo "parent progress pid:{$parentPid}\n";$childList = array(); // 创建消息队列,以及定义消息类型(类似于数据库中的库) $id = ftok(__FILE__,'m'); $msgQueue = msg_get_queue($id); const MSG_TYPE = 1; // 生产者 function producer(){ global $msgQueue; $pid = posix_getpid(); $repeatNum = 5; for ( $i = 1; $i <= $repeatNum; $i++) { $str = "({$pid})progress create! {$i}"; msg_send($msgQueue,MSG_TYPE,$str); $rand = rand(1,3); sleep($rand); } } // 消费者 function consumer(){ global $msgQueue; $pid = posix_getpid(); $repeatNum = 6; for ( $i = 1; $i <= $repeatNum; $i++) { $rel = msg_receive($msgQueue,MSG_TYPE,$msgType,1024,$message); echo "{$message} | consumer({$pid}) destroy \n"; $rand = rand(1,3); sleep($rand); } } function createProgress($callback){ $pid = pcntl_fork(); if ( $pid == -1) { // 创建失败 exit("fork progress error!\n"); } else if ($pid == 0) { // 子进程执行程序 $pid = posix_getpid(); $callback(); exit("({$pid})child progress end!\n"); }else{ // 父进程执行程序 return $pid; } } // 3个写进程 for ($i = 0; $i < 3; $i ++ ) { $pid = createProgress('producer'); $childList[$pid] = 1; echo "create producer child progress: {$pid} \n"; } // 2个写进程 for ($i = 0; $i < 2; $i ++ ) { $pid = createProgress('consumer'); $childList[$pid] = 1; echo "create consumer child progress: {$pid} \n"; } // 等待所有子进程结束 while(!empty($childList)){ $childPid = pcntl_wait($status); if ($childPid > 0){ unset($childList[$childPid]); } } echo "({$parentPid})main progress end!\n";
단 하나의 프로세스만 메시지 대기열의 데이터에 액세스할 수 있으므로 추가 잠금이나 세마포어가 필요하지 않습니다.
2. 세마포어와 공유 메모리
세마포어: 시스템이 제공하는 원자적 연산인 세마포어이며, 동시에 여러분의 프로세스만이 이를 연산할 수 있습니다. 프로세스가 세마포어를 획득하면 프로세스에서 이를 해제해야 합니다.
공유 메모리: 메모리 내에서 시스템이 공개하는 공통 메모리 영역으로, 모든 프로세스가 동시에 액세스할 수 있습니다. 데이터의 일관성을 보장하려면 메모리 영역이 필요합니다. 잠금 또는 세마포어가 됩니다.
아래에서는 메모리의 동일한 값을 수정하는 여러 프로세스를 만듭니다.
$parentPid = posix_getpid(); echo "parent progress pid:{$parentPid}\n"; $childList = array(); // 创建共享内存,创建信号量,定义共享key $shm_id = ftok(__FILE__,'m'); $sem_id = ftok(__FILE__,'s'); $shareMemory = shm_attach($shm_id); $signal = sem_get($sem_id); const SHARE_KEY = 1; // 生产者 function producer(){ global $shareMemory; global $signal; $pid = posix_getpid(); $repeatNum = 5; for ( $i = 1; $i <= $repeatNum; $i++) { // 获得信号量 sem_acquire($signal); if (shm_has_var($shareMemory,SHARE_KEY)){ // 有值,加一 $count = shm_get_var($shareMemory,SHARE_KEY); $count ++; shm_put_var($shareMemory,SHARE_KEY,$count); echo "({$pid}) count: {$count}\n"; }else{ // 无值,初始化 shm_put_var($shareMemory,SHARE_KEY,0); echo "({$pid}) count: 0\n"; } // 用完释放 sem_release($signal); $rand = rand(1,3); sleep($rand); } } function createProgress($callback){ $pid = pcntl_fork(); if ( $pid == -1) { // 创建失败 exit("fork progress error!\n"); } else if ($pid == 0) { // 子进程执行程序 $pid = posix_getpid(); $callback(); exit("({$pid})child progress end!\n"); }else{ // 父进程执行程序 return $pid; } } // 3个写进程 for ($i = 0; $i < 3; $i ++ ) { $pid = createProgress('producer'); $childList[$pid] = 1; echo "create producer child progress: {$pid} \n"; } // 等待所有子进程结束 while(!empty($childList)){ $childPid = pcntl_wait($status); if ($childPid > 0){ unset($childList[$childPid]); } } // 释放共享内存与信号量 shm_remove($shareMemory); sem_remove($signal); echo "({$parentPid})main progress end!\n";
3. 신호
신호는 시스템 호출입니다. 일반적으로 우리가 사용하는 kill 명령은 특정 프로세스에 특정 신호를 보내는 것입니다. liunx/mac에서 kill -l을 실행하여 특정 신호를 확인할 수 있습니다. 다음 예에서 상위 프로세스는 5초 동안 기다린 후 하위 프로세스에 siint 신호를 보냅니다. 하위 프로세스는 신호를 캡처하고 신호 처리 기능으로 처리합니다.
$parentPid = posix_getpid(); echo "parent progress pid:{$parentPid}\n"; // 定义一个信号处理函数 function sighandler($signo) { $pid = posix_getpid(); echo "{$pid} progress,oh no ,I'm killed!\n"; exit(1); } $pid = pcntl_fork(); if ( $pid == -1) { // 创建失败 exit("fork progress error!\n"); } else if ($pid == 0) { // 子进程执行程序 // 注册信号处理函数 declare(ticks=10); pcntl_signal(SIGINT, "sighandler"); $pid = posix_getpid(); while(true){ echo "{$pid} child progress is running!\n"; sleep(1); } exit("({$pid})child progress end!\n"); }else{ // 父进程执行程序 $childList[$pid] = 1; // 5秒后,父进程向子进程发送sigint信号. sleep(5); posix_kill($pid,SIGINT); sleep(5); } echo "({$parentPid})main progress end!\n";
4. 파이프(명명된 파이프)
파이프는 다중 프로세스 통신에 일반적으로 사용되는 수단입니다. 파이프는 명명되지 않은 파이프와 명명된 파이프로 구분되지만, 명명된 파이프는 관련 관계와의 프로세스 간 통신에만 사용할 수 있습니다. 유명한 파이프는 동일한 호스트의 모든 프로세스에서 사용할 수 있습니다. 이곳에서는 유명한 채널만 소개합니다. 다음 예에서는 하위 프로세스가 데이터를 쓰고 상위 프로세스가 데이터를 읽습니다.
// 定义管道路径,与创建管道 $pipe_path = '/data/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); } }
관련 권장 사항:
PHP 프로세스 통신을 기반으로 한 세마포 및 공유 메모리 통신
위 내용은 PHP 프로세스 간 통신에 대한 자세한 설명의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!