webentwicklung-frage-antwort-db.com.de

Hat PHP Threading?

Ich habe folgendes gefunden PECL-Paket namens threads , aber es gibt noch keine Veröffentlichung. Und auf der PHP Website ist nichts los.

125
Thomas Owens

Mir ist nichts bekannt. Das nächstbeste wäre, einfach ein Skript über CLI ein anderes ausführen zu lassen, aber das ist ein bisschen rudimentär. Je nachdem, was Sie versuchen und wie komplex es ist, kann dies eine Option sein oder auch nicht.

40
Wilco

Aus dem PHP - Handbuch für die Erweiterung pthreads :

pthreads ist eine objektorientierte API, die User-Land-Multithreading in PHP ermöglicht. Es enthält alle Tools, die Sie zum Erstellen von Multithread-Anwendungen für das Web oder die Konsole benötigen. PHP - Anwendungen können Threads, Worker und Stackables erstellen, lesen, schreiben, ausführen und synchronisieren.

So unglaublich das auch klingt, es ist völlig wahr. Heutzutage kann PHP Multithreading für diejenigen ausführen, die es ausprobieren möchten.

Die erste Version von PHP4, 22. Mai 2000, PHP, wurde mit einer thread-sicheren Architektur ausgeliefert. Auf diese Weise können mehrere Instanzen des Interpreters in separaten Threads in SAPI-Umgebungen mit mehreren Threads (Server-API) ausgeführt werden. In den letzten 13 Jahren wurde das Design dieser Architektur beibehalten und weiterentwickelt: Seitdem wurde sie in der Produktion auf den weltweit größten Websites eingesetzt.

Threading im User-Land war für das PHP - Team nie ein Problem und bleibt es auch heute. Sie sollten verstehen, dass es in der Welt, in der PHP geschäftlich tätig ist, bereits eine definierte Methode zur Skalierung gibt - fügen Sie Hardware hinzu. Im Laufe der vielen Jahre, in denen PHP existiert, ist die Hardware immer billiger geworden, und so wurde dies für das PHP - Team immer weniger ein Problem. Während es billiger wurde, wurde es auch viel leistungsfähiger; Heutzutage haben unsere Mobiltelefone und Tablets Dual- und Quad-Core-Architekturen und jede Menge RAM, unsere Desktops und Server haben normalerweise 8 oder 16 Kerne, 16 und 32 Gigabyte RAM, obwohl dies nicht immer der Fall ist Zwei innerhalb des Budgets zu haben und zwei Desktops zu haben, ist für die meisten von uns selten nützlich.

Zusätzlich wurde PHP für den Nicht-Programmierer geschrieben, es ist eine Muttersprache vieler Hobbyisten. Der Grund, warum PHP so einfach übernommen wird, ist, dass es eine einfache Sprache ist, die man lernen und schreiben kann. Der Grund, warum PHP heutzutage so zuverlässig ist, ist die enorme Menge an Arbeit, die in sein Design fließt, und jede einzelne Entscheidung, die von der PHP Gruppe getroffen wird. Es ist Zuverlässigkeit und pure Größe, die es nach all den Jahren ins Rampenlicht rücken lässt. wo es Rivalen zu Zeit oder Druck gefallen sind.

Multithread-Programmierung ist für die meisten nicht einfach, selbst mit der kohärentesten und zuverlässigsten API. Es gibt verschiedene Dinge, über die man nachdenken muss, und viele Missverständnisse. Die PHP - Gruppe möchte nicht, dass Multi-Threading für Benutzer ein zentrales Feature ist, es wurde nie ernsthaft beachtet - und das zu Recht. PHP sollte nicht für alle komplex sein.

Alles in allem gibt es immer noch Vorteile, wenn PHP seine produktionsfertigen und getesteten Funktionen nutzt, um das Beste aus dem herauszuholen, was wir haben, wenn das Hinzufügen von mehr nicht immer eine Option ist. und für viele aufgaben wird das nie wirklich gebraucht.

pthreads bietet denjenigen, die es erkunden möchten, eine API, mit der ein Benutzer Multithread-Anwendungen PHP ausführen kann. Die API ist noch in Arbeit und wird als Beta-Level für Stabilität und Vollständigkeit bezeichnet.

Es ist allgemein bekannt, dass einige der Bibliotheken, die PHP verwendet, nicht threadsicher sind. Es sollte dem Programmierer klar sein, dass pthreads dies nicht ändern können und nicht versuchen, es zu versuchen. Jede Bibliothek, die threadsicher ist, kann jedoch wie in jeder anderen threadsicheren Konfiguration des Interpreters verwendet werden.

pthreads verwendet Posix-Threads (auch unter Windows). Das, was der Programmierer erstellt, sind echte Ausführungsthreads. Damit diese Threads jedoch nützlich sind, müssen sie PHP kennen - in der Lage sein, Benutzercode auszuführen, Variablen freizugeben und a nützliche Kommunikationsmittel (Synchronisation). Daher wird jeder Thread mit einer Instanz des Interpreters erstellt, der Interpreter ist jedoch standardmäßig von allen anderen Instanzen des Interpreters isoliert - genau wie Server-API-Umgebungen mit mehreren Threads. pthreads versucht, die Lücke auf gesunde und sichere Weise zu schließen. Viele der Bedenken des Programmierers von Threads in C sind für den Programmierer von pthreads einfach nicht vorhanden, da pthreads von Entwurf her beim Lesen kopiert und beim Schreiben kopiert wird (RAM ist billig), sodass niemals zwei Instanzen manipuliert werden dieselben physischen Daten, aber beide können sich auf Daten in einem anderen Thread auswirken. Die Tatsache, dass PHP Thread-unsichere Funktionen in seiner Kernprogrammierung verwendet, ist völlig irrelevant, Benutzer-Threads und seine Operationen sind absolut sicher.

Warum beim Lesen kopieren und beim Schreiben kopieren:

public function run() {
    ...
    (1) $this->data = $data;
    ...
    (2) $this->other = someOperation($this->data);
    ...
}

(3) echo preg_match($pattern, $replace, $thread->data);

(1) Während eine Lese- und Schreibsperre für den pthreads-Objektdatenspeicher gehalten wird, werden Daten von seinem ursprünglichen Speicherort in den Objektspeicher kopiert. pthreads nicht die refcount der Variablen einzustellen, ist Zend können die Originaldaten befreien, wenn es keine weiteren Verweise darauf sind.

(2) Das Argument zu someOperation verweist auf den Objektspeicher, wobei die ursprünglich gespeicherten Daten, die es selbst als Kopie des Ergebnisses von (1) gibt, erneut für die Engine in einen zval-Container kopiert werden, während hierbei eine Lesesperre aufrechterhalten bleibt Im Objektspeicher wird die Sperre aufgehoben und die Engine kann die Funktion ausführen. Wenn das zval erstellt wird, hat es eine Nachzählung von 0, sodass die Engine die Kopie nach Abschluss des Vorgangs freigeben kann, da keine anderen Verweise darauf vorhanden sind.

(3) Das letzte Argument für preg_match verweist auf den Datenspeicher, es wird eine Lesesperre erhalten, der in (1) festgelegte Datensatz wird in ein zval kopiert, wiederum mit einem Refcount von 0. Die Sperre wird aufgehoben. Der Aufruf von preg_match wird bearbeitet eine Kopie von Daten, dh selbst eine Kopie der Originaldaten.

Wissenswertes:

  • Die Hash-Tabelle des Objektspeichers, in der Daten gespeichert werden, ist threadsicher
    basierend auf dem mit PHP ausgelieferten TsHashTable von Zend.

  • Der Objektspeicher verfügt über eine Lese- und Schreibsperre. Für die TsHashTable ist eine zusätzliche Zugriffssperre vorgesehen, sodass bei Bedarf (und mit var_dump/print_r auch direkt auf Eigenschaften zugegriffen werden kann, auf die die PHP - Engine verweisen möchte) Pthreads kann die TsHashTable außerhalb der definierten API manipulieren.

  • Die Sperren werden nur gehalten, während die Kopiervorgänge stattfinden, und wenn die Kopien erstellt wurden, werden die Sperren in einer vernünftigen Reihenfolge freigegeben.

Dies bedeutet:

  • Bei einem Schreibvorgang wird nicht nur eine Lese- und Schreibsperre gehalten, sondern auch eine zusätzliche Zugriffssperre. Die Tabelle selbst ist gesperrt. Es gibt keine Möglichkeit, wie ein anderer Kontext sie sperren, lesen, schreiben oder beeinflussen kann.

  • Bei einem Lesevorgang wird nicht nur die Lesesperre, sondern auch die zusätzliche Zugriffssperre gehalten, und die Tabelle wird wieder gesperrt.

Keine zwei Kontexte können physisch oder gleichzeitig auf dieselben Daten aus dem Objektspeicher zugreifen, aber in einem beliebigen Kontext mit einer Referenz vorgenommene Schreibvorgänge wirken sich auf die in einem beliebigen Kontext mit einer Referenz gelesenen Daten aus.

Dies hat nichts mit Architektur zu tun und der einzige Weg zu existieren ist das Nebeneinander. Diejenigen, die ein bisschen versiert sind, werden sehen, dass hier viel kopiert wird, und sie werden sich fragen, ob das eine gute Sache ist. In einer dynamischen Laufzeit wird ziemlich viel kopiert, das ist die Dynamik einer dynamischen Sprache. pthreads wird auf der Ebene des Objekts implementiert, da eine gute Kontrolle über ein Objekt erzielt werden kann. Methoden - der Code, den der Programmierer ausführt - haben jedoch einen anderen Kontext, der frei von Sperren und Kopien ist - den Gültigkeitsbereich der lokalen Methode. Der Objektbereich im Fall eines pthreads-Objekts sollte als eine Möglichkeit zum Teilen von Daten zwischen Kontexten behandelt werden. Dies ist der Zweck. In diesem Sinne können Sie Techniken anwenden, um das Sperren des Objektspeichers zu vermeiden, es sei denn, dies ist erforderlich. Sie können beispielsweise lokale Bereichsvariablen an andere Methoden in einem Thread-Objekt übergeben, anstatt sie bei der Ausführung aus dem Objektspeicher kopieren zu lassen.

Die meisten Bibliotheken und Erweiterungen, die für PHP verfügbar sind, sind Thin Wrapper für Drittanbieter. Die Kernfunktionalität von PHP ist bis zu einem gewissen Grad dieselbe. pthreads ist keine dünne Hülle um Posix-Threads. Es ist eine Threading-API, die auf Posix-Threads basiert. Es hat keinen Sinn, Threads in PHP zu implementieren, die die Benutzer nicht verstehen oder nicht verwenden können. Es gibt keinen Grund, warum eine Person, die nicht weiß, was ein Mutex ist oder tut, nicht in der Lage sein sollte, alle ihre Fähigkeiten und Ressourcen zu nutzen. Ein Objekt funktioniert wie ein Objekt. Wo jedoch zwei Kontexte ansonsten kollidieren, bietet pthreads Stabilität und Sicherheit.

Jeder, der in Java gearbeitet hat, sieht die Ähnlichkeiten zwischen einem pthreads-Objekt und dem Threading in Java. Dieselben Leute haben zweifellos einen Fehler namens ConcurrentModificationException gesehen - da dies nach einem von der Laufzeit Java ausgelösten Fehler klingt Wenn zwei Threads gleichzeitig dieselben physischen Daten schreiben. Ich verstehe, warum es existiert, aber es verblüfft mich, dass die Laufzeit bei so billigen Ressourcen in der Lage ist, die Parallelität genau zu dem Zeitpunkt zu erkennen, zu dem die Sicherheit für den Benutzer, den sie wählt, erreicht werden kann einen möglicherweise schwerwiegenden Fehler zur Laufzeit auslösen, anstatt die Ausführung und den Zugriff auf die Daten zu verwalten.

Von pthreads werden keine solchen dummen Fehler ausgegeben, die API wurde geschrieben, um das Threading so stabil und kompatibel wie möglich zu machen, glaube ich.

Multithreading ist nicht mit der Verwendung einer neuen Datenbank vergleichbar. Beachten Sie daher jedes Wort im Handbuch und die mit pthreads gelieferten Beispiele.

Zuletzt aus dem PHP Handbuch:

pthreads war und ist ein experiment mit ziemlich guten ergebnissen. Sämtliche Einschränkungen oder Funktionen können sich jederzeit ändern. Das ist die Natur des Experimentierens. Es gibt aus gutem Grund Einschränkungen, die oft von der Implementierung auferlegt werden. Ziel von pthreads ist es, eine benutzerfreundliche Lösung für das Multitasking in PHP auf jeder Ebene bereitzustellen. In der Umgebung, die von pthreads ausgeführt wird, sind einige Einschränkungen und Einschränkungen erforderlich, um eine stabile Umgebung bereitzustellen.

176
Joe Watkins

Hier ist ein Beispiel für das, was Wilco vorgeschlagen hat:

$cmd = 'Nohup Nice -n 10 /usr/bin/php -c /path/to/php.ini -f /path/to/php/file.php action=generate var1_id=23 var2_id=35 gen_id=535 > /path/to/log/file.log & echo $!';
$pid = Shell_exec($cmd);

Grundsätzlich führt dies das Skript PHP in der Befehlszeile aus, gibt jedoch sofort die PID zurück und wird dann im Hintergrund ausgeführt. (Das echo $! Stellt sicher, dass nichts anderes als die PID zurückgegeben wird.) Auf diese Weise kann Ihr PHP - Skript fortgesetzt oder beendet werden, wenn Sie dies möchten. Wenn ich dies verwendet habe, habe ich den Benutzer auf eine andere Seite umgeleitet, auf der alle 5 bis 60 Sekunden ein AJAX -Aufruf erfolgt, um zu überprüfen, ob der Bericht noch ausgeführt wird. (Ich habe eine Tabelle zum Speichern der gen_id und des zugehörigen Benutzers.) Das Überprüfungsskript führt Folgendes aus:

exec('ps ' . $pid , $processState);
if (count($processState) < 2) {
     // less than 2 rows in the ps, therefore report is complete
}

Hier gibt es einen kurzen Beitrag zu dieser Technik: http://nsaunders.wordpress.com/2007/01/12/running-a-background-process-in-php/

48
Darryl Hein

Kurz gesagt: Ja, es gibt Multithreading in PHP, aber Sie sollten stattdessen Multiprocessing verwenden.

Hintergrundinformationen: Threads vs. Prozesse

Die Unterscheidung von Threads und Prozessen ist immer etwas verwirrend, daher beschreibe ich kurz beide:

  • Ein Thread ist eine Folge von Befehlen, die die CPU verarbeiten wird. Die einzigen Daten, aus denen es besteht, sind Programmzähler. Jeder CPU-Kern verarbeitet jeweils nur einen Thread, kann jedoch über die Zeitplanung zwischen der Ausführung verschiedener Threads wechseln.
  • Ein Prozess ist eine Gruppe von gemeinsam genutzten Ressourcen. Das heißt, es besteht aus einem Teil des Speichers, Variablen, Objektinstanzen, Dateihandles, Mutexen, Datenbankverbindungen usw. Jeder Prozess enthält auch einen oder mehrere Threads. Alle Threads desselben Prozesses verwenden dieselben Ressourcen, sodass Sie in einem Thread eine Variable verwenden können, die Sie in einem anderen Thread erstellt haben. Wenn diese Threads Teile von zwei verschiedenen Prozessen sind, können sie nicht direkt auf die anderen Ressourcen zugreifen. In diesem Fall benötigen Sie prozessübergreifende Kommunikation durch z. Rohre, Feilen, Steckdosen ...

Multiprozessing

Sie können paralleles Rechnen erreichen, indem Sie mit PHP neue Prozesse erstellen (die auch einen neuen Thread enthalten). Wenn Ihre Threads nicht viel Kommunikation oder Synchronisation benötigen, ist dies Ihre Wahl, da die Prozesse isoliert sind und sich nicht gegenseitig in ihrer Arbeit stören können. Selbst wenn einer abstürzt, geht das die anderen nichts an. Wenn Sie viel Kommunikation benötigen, sollten Sie unter "Multithreading" weiterlesen oder - leider - eine andere Programmiersprache in Betracht ziehen, da die Kommunikation und Synchronisation zwischen den Prozessen viel Hautfarbe hervorruft.

In PHP haben Sie zwei Möglichkeiten, einen neuen Prozess zu erstellen:

Lassen Sie das Betriebssystem dies für Sie tun : Sie können Ihrem Betriebssystem anweisen, einen neuen Prozess zu erstellen und ein neues (oder dasselbe) PHP-Skript darin auszuführen .

  • für Linux können Sie Folgendes verwenden oder Darryl Heins Antwort in Betracht ziehen:

    $cmd = 'Nice php script.php 2>&1 & echo $!';
    pclose(popen($cmd, 'r'));
    
  • für Windows können Sie dies verwenden:

    $cmd = 'start "processname" /MIN /belownormal cmd /c "script.php 2>&1"';
    pclose(popen($cmd, 'r'));
    

Mach es selbst mit einer Gabel : php bietet auch die Möglichkeit, das Gabeln durch die Funktion pcntl_fork () zu benutzen. Ein gutes Tutorial, wie man das macht, findet sich hier aber ich empfehle dringend, es nicht zu benutzen, da Gabel ist ein Verbrechen gegen die Menschlichkeit und besonders gegen oop.

Multithreading

Mit Multithreading können alle Ihre Threads ihre Ressourcen gemeinsam nutzen, sodass Sie problemlos miteinander kommunizieren und sie synchronisieren können, ohne viel Aufwand zu verursachen. Auf der anderen Seite muss man wissen, was man tut, da Rennbedingungen und Deadlocks leicht zu produzieren, aber sehr schwer zu debuggen sind.

Standard-PHP bietet kein Multithreading, aber es gibt eine (experimentelle) Erweiterung, die tatsächlich - pthreads ausführt. Seine API-Dokumentation machte es sogar zu php.net . Damit kannst du ein paar Sachen machen wie in echten Programmiersprachen :-) so:

class MyThread extends Thread {
    public function run(){
        //do something time consuming
    }
}

$t = new MyThread();
if($t->start()){
    while($t->isRunning()){
        echo ".";
        usleep(100);
    }
    $t->join();
}

Für Linux gibt es hier bei stackoverflow's ein Installationsanleitung .

Für Fenster gibt es jetzt eines:

  • Zuerst benötigen Sie die thread-sichere Version von PHP.
  • Sie benötigen die vorkompilierten Versionen beider pthreads und ihrer PHP-Erweiterung. Sie können heruntergeladen werden hier . Stellen Sie sicher, dass Sie die Version herunterladen, die mit Ihrer PHP-Version kompatibel ist.
  • Kopieren Sie die Datei php_pthreads.dll (von der soeben heruntergeladenen Zip-Datei) in Ihren PHP-Erweiterungsordner ([phpDirectory]/ext).
  • Kopieren Sie die Datei pthreadVC2.dll in [phpDirectory] (den Stammordner - nicht den Erweiterungsordner).
  • Bearbeiten Sie die Datei [phpDirectory] /php.ini und fügen Sie die folgende Zeile ein

    extension=php_pthreads.dll
    
  • Testen Sie es mit dem obigen Skript mit etwas Schlaf oder etwas genau dort, wo der Kommentar ist.

Und jetzt das große [~ # ~] aber [~ # ~] : Obwohl dies wirklich funktioniert, war PHP ursprünglich nicht für Multithreading gemacht. Es gibt eine thread-sichere Version von PHP und ab v5.4 scheint es fast fehlerfrei zu sein, aber die Verwendung von PHP in einer Umgebung mit mehreren Threads ist immer noch im PHP-Handbuch wird davon abgeraten (aber vielleicht sind sie es auch habe gerade ihr Handbuch dazu noch nicht aktualisiert). Ein viel größeres Problem könnte sein, dass viele häufig vorkommende Erweiterungen sind nicht threadsicher . Sie könnten Threads mit dieser PHP-Erweiterung bekommen, aber die Funktionen, von denen Sie abhängig sind, sind immer noch nicht thread-sicher, so dass Sie wahrscheinlich auf Race-Bedingungen, Deadlocks usw. in Code stoßen, den Sie selbst nicht geschrieben haben ...

24

Sie können pcntl_fork () verwenden, um etwas Ähnliches wie Threads zu erreichen. Technisch sind es getrennte Prozesse, so dass die Kommunikation zwischen den beiden mit Threads nicht so einfach ist, und ich glaube, dass es nicht funktionieren wird, wenn PHP von Apache aufgerufen wird.

17
davr

Wenn es jemanden interessiert, habe ich php_threading wiederbelebt (nicht dasselbe wie Threads, aber ähnlich) und ich habe es tatsächlich bis zu dem Punkt, an dem es funktioniert (etwas) Gut!

Projektseite

Download (für Windows PHP 5.3 VC9 TS)

Beispiele

README

13
Alec Gorge

pcntl_fork() ist das, wonach Sie suchen, aber der Prozess des Gabelns führt kein Threading durch. Sie haben also das Problem des Datenaustauschs. Um sie zu lösen, können Sie PHP-Semaphor-Funktionen verwenden ( http://www.php.net/manual/de/ref.sem.php ) Segmente.

Wie auch immer, eine Strategie, die ich in einem Web-Framework verwende, das ich entwickle und das ressourcenintensive Blöcke einer Webseite (wahrscheinlich mit externen Anfragen) parallel lädt: Ich stelle mich in eine Job-Warteschlange, um zu wissen, auf welche Daten ich warte, und verzweige mich dann aus den Jobs für jeden Prozess. Anschließend speichern sie ihre Daten im Apc-Cache unter einem eindeutigen Schlüssel, auf den der übergeordnete Prozess zugreifen kann. Sobald alle Daten da sind, geht es weiter. Ich benutze simple usleep(), um zu warten, da in Apache keine Kommunikation zwischen Prozessen möglich ist (Kinder verlieren die Verbindung zu ihren Eltern und werden zu Zombies ...). Das bringt mich zum letzten Punkt: Es ist wichtig, jedes Kind selbst zu töten! Es gibt auch Klassen, die verarbeiten, aber Daten behalten. Ich habe sie nicht untersucht, aber das zend-Framework hat eine, und sie machen normalerweise langsamen, aber zuverlässigen Code. Sie finden es hier: http://zendframework.com/manual/1.9/en/zendx.console.process.unix.overview.html Ich denke, sie verwenden Shm-Segmente! na last but not least gibt es einen fehler auf dieser zend website, kleiner fehler im beispiel.

while ($process1->isRunning() && $process2->isRunning()) {
    sleep(1);
}
should of course be:
while ($process1->isRunning() || $process2->isRunning()) {
    sleep(1);
}
7
The Surrican

Nur ein Update, es sieht so aus, als ob PHP Jungs arbeiten an einem unterstützenden Thread und es ist jetzt verfügbar.

Hier ist der Link dazu: http://php.net/manual/en/book.pthreads.php

6
happyhardik

Es gibt eine Threading-Erweiterung, die auf PThreads basiert und bei https://github.com/krakjoe/pthreads sehr vielversprechend aussieht

6
JasonDavis

Ich habe eine PHP Threading-Klasse, die seit über zwei Jahren in einer Produktionsumgebung fehlerfrei läuft.

BEARBEITEN: Dies ist jetzt als composer Bibliothek und als Teil meines MVC Frameworks, Hazaar MVC, verfügbar.

Siehe: https://git.hazaarlabs.com/hazaar/hazaar-thread

5
Jamie Carl

Ich weiß, dass dies eine sehr alte Frage ist, aber Sie können sich http://phpthreadlib.sourceforge.net/ ansehen

Bidirektionale Kommunikation, Unterstützung für Win32 und keine Erweiterungen erforderlich.

2
Unsigned

Schon mal was von appserver von techdivision gehört?

Es ist in PHP geschrieben und fungiert als App-Server, der Multithreads für stark frequentierte PHP-Anwendungen verwaltet. Ist noch in der Beta aber sehr vielversprechend.

1
user2627170