Heim  >  Artikel  >  Backend-Entwicklung  >  PHP implementiert Multiprozess und Multithreading

PHP implementiert Multiprozess und Multithreading

不言
不言Original
2018-05-03 11:07:142809Durchsuche

Dieser Artikel stellt hauptsächlich die Implementierung von Multiprozessen und Multithreading in PHP vor. Er hat einen gewissen Referenzwert. Jetzt kann ich ihn mit allen teilen, die ihn brauchen.

Anleitung für Neulinge.


Verwaister Prozess: Ein übergeordneter Prozess wird beendet, während einer oder mehrere seiner untergeordneten Prozesse noch ausgeführt werden. Diese untergeordneten Prozesse werden dann zu verwaisten Prozessen. Der verwaiste Prozess wird vom Init-Prozess übernommen (Prozessnummer ist 1) und der Init-Prozess schließt die Statuserfassungsarbeit für ihn ab.

Zombie-Prozess: Ein Prozess verwendet fork, um einen untergeordneten Prozess zu erstellen, wenn der untergeordnete Prozess beendet wird und der übergeordnete Prozess nicht „wait“ oder „waitpid“ aufruft, um den Status zu erhalten Informationen des untergeordneten Prozesses. Dann wird der Prozessdeskriptor des untergeordneten Prozesses weiterhin im System gespeichert. Dieser Prozess wird als Zombie-Prozess bezeichnet.

Gefahren des Zombie-Prozesses: Wenn der Prozess nicht wait/waitpid aufruft, Dann werden die gespeicherten Informationen nicht freigegeben und ihre Prozessnummer wird immer belegt. Die Prozessnummer, die vom System verwendet werden kann, ist jedoch begrenzt durch den Mangel an verfügbaren Prozessnummern kann das System keine neuen Prozesse generieren. Dies ist der Schaden von Zombie-Prozessen und sollte vermieden werden. Jeder untergeordnete Prozess (außer init) verschwindet nicht sofort nach exit(), sondern hinterlässt eine Datenstruktur, die als Zombie-Prozess (Zombie) bezeichnet wird und auf die Verarbeitung durch den übergeordneten Prozess wartet.

Die Lösung für den generierten Zombie-Prozess: Töten Sie den übergeordneten Prozess und den Zombie-Prozess Es wird generiert. Werden zu verwaisten Prozessen, diese verwaisten Prozesse werden vom Init-Prozess übernommen, und der Init-Prozess wartet () auf diese verwaisten Prozesse und gibt die von ihnen belegten Ressourcen in der Systemprozesstabelle frei.

Lösung für den Zombie-Prozess

(1) Durch den Signalmechanismus

Wenn das Kind Der Prozess wird beendet. Senden Sie das SIGCHILD-Signal an den übergeordneten Prozess. Der übergeordnete Prozess verarbeitet das SIGCHILD-Signal. Rufen Sie „wait“ in der Signalverarbeitungsfunktion auf, um den Zombie-Prozess zu verarbeiten.

(2) zweimal verzweigen

Abschnitt 8.6 von „Erweiterte Programmierung in Unix-Umgebungen“ ist sehr detailliert. Das Prinzip besteht darin, den untergeordneten Prozess in einen verwaisten Prozess umzuwandeln, sodass sein übergeordneter Prozess zu einem Init-Prozess wird und der Zombie-Prozess über den Init-Prozess verarbeitet werden kann.


Vergleich zwischen Multiprozess und Multithread

Kontrastabmessungen

Multiprozess

Multi- Thread

Zusammenfassung

Datenaustausch, Synchronisierung

Der Datenaustausch ist komplex und erfordert IPC; die Daten werden getrennt und die Synchronisierung ist einfach

Da Prozessdaten gemeinsam genutzt werden, ist die Datenfreigabe einfach, aber aus diesem Grund ist auch die Synchronisierung kompliziert

Jedes hat seine eigenen Vorteile

Speicher, CPU

Beanspruchen viel Speicher, komplexes Umschalten, geringe CPU-Auslastung

Beansprucht wenig Speicher, einfaches Umschalten, hohe CPU-Auslastung

Thread-Dominanz

Erstellen , zerstören, wechseln

Erstellung, Zerstörung und Wechsel sind komplex und langsam

Erstellung, Zerstörung und Wechsel sind einfach und schnell

Threadbelegung ausgezeichnet

Programmierung und Debugging

Einfache Programmierung und einfaches Debuggen

Komplexe Programmierung, kompliziertes Debuggen

Prozessdominanz

Zuverlässigkeit

Prozesse beeinflussen sich nicht gegenseitig

Wenn ein Thread hängen bleibt, bleibt der gesamte Prozess hängen

Der Prozess nutzt die Vorteile

Verteilt

Geeignet für die Multi-Core- und Multi-Machine-Verteilung; Eine Maschine reicht nicht aus, es ist einfacher, auf mehrere Maschinen zu erweitern

An die Multi-Core-Verteilung angepasst

Prozessdominanz

1) Priorisierte Threads, die häufig erstellt und gelöscht werden müssen

Den Grund finden Sie im Vergleich oben.

Die häufigste Anwendung dieses Prinzips ist der Webserver. Eine Verbindung erstellt einen Thread, und wenn er getrennt wird, wird der Thread zerstört. Wenn ein Prozess verwendet wird, sind die Kosten für die Erstellung und Zerstörung unerträglich 🎜>

2) Priorisieren Sie die Verwendung von Threads, die eine große Menge an Berechnungen erfordern

Die sogenannte große Menge an Berechnungen verbraucht natürlich viel CPU und Schalter In diesem Fall sind Threads am besten geeignet.

Die gebräuchlichsten Prinzipien dieser Art sind Bildverarbeitung und Algorithmenverarbeitung.

3) Threads werden für die Verarbeitung starker Korrelationen verwendet, und Prozesse werden für die Verarbeitung schwacher Korrelationen verwendet

Was sind starke Korrelation und schwache Korrelation? Es ist schwierig, es theoretisch zu definieren, aber Sie können es anhand eines einfachen Beispiels verstehen.

Ein allgemeiner Server muss die folgenden Aufgaben ausführen: Senden und Empfangen von Nachrichten, Nachrichtenverarbeitung. „Nachrichtensenden und -empfangen“ und „Nachrichtenverarbeitung“ sind schwach verwandte Aufgaben, und „Nachrichtenverarbeitung“ kann in „Nachrichtendekodierung“ und „Geschäftsverarbeitung“ unterteilt werden. Diese beiden Aufgaben sind relativ viel enger miteinander verbunden. Daher können „Nachrichtensenden und -empfangen“ und „Nachrichtenverarbeitung“ in separaten Prozessen entworfen werden, und „Nachrichtendekodierung“ und „Geschäftsverarbeitung“ können in separaten Threads entworfen werden.

Natürlich ist diese Aufteilungsmethode nicht statisch und kann auch entsprechend der tatsächlichen Situation angepasst werden.

4) Es kann auf verteilte Benutzerprozesse mit mehreren Maschinen und verteilte Benutzerthreads mit mehreren Kernen erweitert werden.

Bitte sehen Sie sich den Vergleich oben für den Grund an.

5) Wenn alle Anforderungen erfüllt sind, verwenden Sie die Methode, mit der Sie am besten vertraut sind und die Sie am besten können.

Was „Datenfreigabe, Synchronisierung“, „Programmierung, Debugging“ betrifft „Wie man zwischen der sogenannten „Komplexität und Einfachheit“ in den Dimensionen „Zuverlässigkeit“ wählen kann, kann ich nur sagen: Es gibt keine klare Auswahlmethode. Aber ich kann Ihnen ein Auswahlprinzip nennen: Wenn sowohl Multi-Processing als auch Multi-Threading die Anforderungen erfüllen können, dann wählen Sie das, mit dem Sie am besten vertraut sind und das Sie am besten können.

Was daran erinnert werden muss: Obwohl ich so viele Auswahlprinzipien angegeben habe, sind tatsächliche Anwendungen im Grunde eine Kombination aus „Prozess + Thread“.

Ressourcenverbrauch:

Aus Sicht des Kernels besteht der Zweck des Prozesses darin, als Grundlage für die Zuweisung von Systemressourcen zu dienen (CPU-Zeit, Speicher usw.) Einheit. Ein Thread ist ein Ausführungsstrom eines Prozesses und die Grundeinheit der CPU-Planung und -Verteilung. Es handelt sich um eine Grundeinheit, die kleiner als ein Prozess ist und unabhängig ausgeführt werden kann.

Threads nutzen untereinander denselben Adressraum und teilen sich die meisten Daten. Der zum Starten eines Threads benötigte Speicherplatz ist viel kürzer als der zum Starten eines Prozesses . Viel weniger Zeit als der Zeitaufwand für den Wechsel zwischen Prozessen. Laut Statistik beträgt der Overhead eines Prozesses im Allgemeinen etwa das 30-fache des Overheads eines Threads. Auf bestimmten Systemen können diese Daten natürlich erheblich unterschiedlich sein.

Kommunikationsmethode:

Die einzige Möglichkeit, Daten zwischen Prozessen zu übertragen, ist die Kommunikation, was zeitaufwändig und unbequem ist. Die meisten Thread-Zeitdaten werden gemeinsam genutzt (nicht innerhalb der Thread-Funktion), was schnell und bequem ist. Für die Datensynchronisierung sind jedoch Sperren erforderlich, und statischen Variablen sollte besondere Aufmerksamkeit gewidmet werden.

Thread-eigene Vorteile:

Verbesserung der Anwendungsreaktion, wodurch Systeme mit mehreren CPUs effizienter werden. Das Betriebssystem stellt sicher, dass unterschiedliche Threads auf unterschiedlichen CPUs ausgeführt werden, wenn die Anzahl der Threads nicht größer ist als die Anzahl der CPUs.

Verbesserung der Programmstruktur. Ein langer und komplexer Prozess kann in mehrere Threads unterteilt werden und in mehrere unabhängige oder halbunabhängige laufende Teile umgewandelt werden. Ein solches Programm ist leichter zu verstehen und zu ändern.

1. [Code] PHP implementiert einen Multiprozess-Parallelbetrieb (kann als Daemon verwendet werden)

/**
 * 入口函数
 * 将此文件保存为 ProcessOpera.php
 * 在terminal中运行 /usr/local/php/bin/php ProcessOpera.php & 
 * 查看进程 ps aux|grep php
 */
 
 
ProcessOpera("runCode", array(), 8);
 
/**
 * run Code
 */
function runCode($opt = array()) {
   //需要在守护进程中运行的代码
}
 
/**
 * $func为子进程执行具体事物的函数名称
 * $opt为$func的参数 数组形式
 * $pNum 为fork的子进程数量
 */
function ProcessOpera($func, $opts = array(), $pNum = 1) {
    while(true) {
        $pid = pcntl_fork();
        if($pid == -1) {
            exit("pid fork error");
        }   
        if($pid) {
            static $execute = 0;
            $execute++;
            if($execute >= $pNum) {
                pcntl_wait($status);
                $execute--;
            }   
        } else {
            while(true) {
                //somecode
                $func($opts);
                sleep(1);
            }   
            exit(0);
        }   
    }   
}

2. [Code] PHP implementiert einen Multithread-Betrieb

class My extends Thread {
    protected $name;
    public $runing;
    function __construct($name){
        $this->runing=1;
        $this->param=0;
        $this->name=$name;
    }
    public function run() {
        while($this->runing){
            if($this->param){
                $time=rand(1,5);
                echo 'I am thread '.$this->name.',pid: '.$this->getCreatorId().",param: {$this->param},need {$time}s\n"; 
                sleep($time);
                $this->param=0;
            }else{
                echo "Thread {$this->name} waiting...\n";
            }
            sleep(1);
        }
    }
}
$pool=array();
$pool[]=new My('a');
$pool[]=new My('b');
$pool[]=new My('c');
//开启所有线程
foreach ($pool as $w) {
    $w->start();
}
//派发任务
unset($w);
for($i=1;$i<10;$i++){
    $woker_content=$i;
    while(1){
        foreach($pool as $w){
            if(!$w->param){
                $w->param=$woker_content;
                echo "Thread {$w->name} empty,put param {$woker_content}.\n";
                break 2;
            }
        }
        sleep(1);    
    }
}


unset($w);
while(count($pool)){
    foreach ($pool as $k => $w) {
        if(!$w->param){
            $w->runing=false;
            unset($pool[$k]);
            echo "Thread {$w->name} end,exit!\n";
        }
    }
    sleep(1);
}


echo &#39;All thread end!&#39;;

Verwandte Empfehlungen:

Detaillierte Erläuterung von fünf Möglichkeiten zur Implementierung geplanter Aufgaben in PHP


Das obige ist der detaillierte Inhalt vonPHP implementiert Multiprozess und Multithreading. 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