Heim  >  Artikel  >  Backend-Entwicklung  >  Detaillierte Erläuterung der PHP-Interprozesskommunikation

Detaillierte Erläuterung der PHP-Interprozesskommunikation

小云云
小云云Original
2018-03-14 15:18:455202Durchsuche

Ein Prozess ist eine laufende Aktivität eines Programms mit unabhängigen Funktionen für eine bestimmte Datensammlung. Mit anderen Worten, es ist die Grundeinheit eines Programms, wenn das System mehrere CPUs plant. Prozess ist für die meisten Sprachen kein unbekanntes Konzept, und als „die beste Sprache der Welt, PHP“ ist es sicherlich eine Ausnahme.

Umgebung

Der Prozess in PHP wird in Form von Erweiterungen abgeschlossen. Durch diese Erweiterungen können wir eine Reihe von Aktionen im Prozess problemlos abschließen.

  • pcntl-Erweiterung: Die Hauptprozesserweiterung, der Abschlussprozess wird im Wartevorgang erstellt.

  • Posix-Erweiterung: Vervollständigen Sie die allgemeine API für Posix-kompatible Maschinen, z. B. zum Abrufen der Prozess-ID, zum Beenden von Prozessen usw.

  • sysvmsg-Erweiterung: eine Nachrichtenwarteschlange, die die System-v-Interprozesskommunikation implementiert.

  • sysvsem-Erweiterung: implementiert System-V-Semaphor.

  • sysvshm-Erweiterung: implementiert den gemeinsam genutzten Speicher von System V.

  • Sockets-Erweiterung: implementiert Socket-Kommunikation.

Diese Erweiterungen können nur unter Linux/Mac verwendet werden und werden unter Windows nicht unterstützt. Abschließend wird empfohlen, dass die PHP-Version 5.5+ ist.

Einfaches Beispiel

Ein einfaches PHP-Mehrprozessbeispiel In diesem Beispiel gibt es einen untergeordneten Prozess und einen übergeordneten Prozess. Der untergeordnete Prozess gibt fünfmal aus und beendet das Programm.

$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!";

Perfekt, endlich einen untergeordneten Prozess und einen übergeordneten Prozess erstellt. Ist es vorbei? Nein, jeder Prozess ist unabhängig voneinander, es gibt keine Schnittmenge und der Anwendungsbereich ist stark eingeschränkt. Was tun? Nutzen wir die Interprogress-Kommunikation.

4. Interprozesskommunikation (IPC)

Zu den Prozesskommunikationsmethoden in Linux gehören normalerweise: Nachrichtenwarteschlange, Semaphor, gemeinsam genutzter Speicher, Signal, Pipe und Socket.

1. Nachrichtenwarteschlange

Die Nachrichtenwarteschlange ist eine im Speicher gespeicherte Warteschlange. Der folgende Code erstellt drei Produzenten-Unterprozesse und zwei Verbraucher-Unterprozesse. Diese 5 Prozesse kommunizieren über die Nachrichtenwarteschlange.

$parentPid = posix_getpid();
echo "parent progress pid:{$parentPid}\n";$childList = array();
// 创建消息队列,以及定义消息类型(类似于数据库中的库)
$id = ftok(__FILE__,&#39;m&#39;);
$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(&#39;producer&#39;);
    $childList[$pid] = 1;
    echo "create producer child progress: {$pid} \n";
}
// 2个写进程
for ($i = 0; $i < 2; $i ++ ) {
    $pid = createProgress(&#39;consumer&#39;);
    $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";

Da nur ein Prozess auf die Daten in der Nachrichtenwarteschlange zugreifen kann, sind keine zusätzlichen Sperren oder Semaphoren erforderlich.

2. Semaphor und gemeinsamer Speicher

Semaphor: Es handelt sich um eine vom System bereitgestellte atomare Operation, die nur von Ihrem Prozess gleichzeitig ausgeführt werden kann. Wenn ein Prozess ein Semaphor erhält, muss es vom Prozess freigegeben werden.

Gemeinsamer Speicher: Es handelt sich um einen vom System geöffneten gemeinsamen Speicherbereich. Auf diesen Bereich können gleichzeitig mehrere Prozesse zugreifen. Es ist notwendig, diesen Speicherbereich zu sperren oder zu semaphorieren.

Nachfolgend werden mehrere Prozesse erstellt, um denselben Wert im Speicher zu ändern.

$parentPid = posix_getpid();
echo "parent progress pid:{$parentPid}\n";
$childList = array();
 
// 创建共享内存,创建信号量,定义共享key
$shm_id = ftok(__FILE__,&#39;m&#39;);
$sem_id = ftok(__FILE__,&#39;s&#39;);
$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(&#39;producer&#39;);
    $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. Signal

Ein Signal ist ein Systemaufruf. Normalerweise besteht der von uns verwendete Kill-Befehl darin, ein bestimmtes Signal an einen bestimmten Prozess zu senden. Sie können die spezifischen Signale überprüfen, indem Sie kill -l in liunx/mac ausführen. Im folgenden Beispiel wartet der übergeordnete Prozess 5 Sekunden und sendet das Signatursignal an den untergeordneten Prozess. Der untergeordnete Prozess erfasst das Signal und verarbeitet es mit der Signalverarbeitungsfunktion.

$parentPid = posix_getpid();
echo "parent progress pid:{$parentPid}\n";
 
// 定义一个信号处理函数
function sighandler($signo) {
    $pid = posix_getpid();
    echo "{$pid} progress,oh no ,I&#39;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. Pipes (benannte Pipes)

Pipes sind ein häufig verwendetes Mittel zur Multiprozesskommunikation. Pipes werden in unbenannte Pipes unterteilt, und benannte Pipes können nur verwendet werden für diejenigen mit Verwandtschaftsbeziehungen. Named Pipes können für jeden Prozess auf demselben Host verwendet werden. Hier werden nur bekannte Sender vorgestellt. Im folgenden Beispiel schreibt der untergeordnete Prozess Daten und der übergeordnete Prozess liest Daten.

// 定义管道路径,与创建管道
$pipe_path = &#39;/data/test.pipe&#39;;
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,&#39;w&#39;);
    while (true){
        fwrite($file,&#39;hello world&#39;);
        $rand = rand(1,3);
        sleep($rand);
    }
    exit(&#39;child end!&#39;);
}else{
    // 父进程,从管道读数据
    $file = fopen($pipe_path,&#39;r&#39;);
    while (true){
        $rel = fread($file,20);
        echo "{$rel}\n";
        $rand = rand(1,2);
        sleep($rand);
    }
}

Verwandte Empfehlungen:

So implementieren Sie die PHP-Prozesssperre

Zusammenfassung der zu beachtenden Punkte zum PHP-Prozess Kommunikation

Semaphor- und Shared-Memory-Kommunikation basierend auf PHP-Prozesskommunikation

Das obige ist der detaillierte Inhalt vonDetaillierte Erläuterung der PHP-Interprozesskommunikation. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn