Panikstörung. Für welche Taten, die Sie im Rausch begangen haben, schämen Sie sich sehr? Ergebnisse des Leistungstests


02.10.2011, 21:27

Weil sie einen Mann geschlagen und sein T-Shirt an einen Baum gehängt hat. Und sie hat einen Idioten ein paar Kilometer weit gefahren, und als er hingefallen ist, hat sie angefangen, auf ihn zu pinkeln. Aber sie haben es verdient.

Ich in Großunternehmen blieb bei dem Mädchen und sagte, dass ihr Freund beim Ausverkauf Bananen und Schalen auf allen Knien im Marshkat gekauft und auch gegessen habe, und ich veranstalte auch ständig Lesbenshows in Bars, einmal unter den Röcken der Kellnerinnen im VIP-Club, in den ich geschaut habe und Ich habe Kommentare abgegeben, aber im Allgemeinen bin ich ein schlechter Trinker. Ich vergesse sofort, dass ich es liebe, wenn die Leute sagen: „Wenn du aufwachst und dich schämst, aber du weißt nicht mehr genau, warum“ über mich

Nach dem letzten Drink schäme ich mich:
1. schrie dem Mann vom Balkon aus zu: „Lutsch es!“
2. eine Zigarette gegessen
3. warf Äpfel
4. rief den Kerl an und sagte ihm, dass ich ihm keinen unhöflichen Sex geben würde
5. ertrunkene Grundeln in Grapefruitsaft
6. rief meine Mutter an und sagte mir, dass ich nüchtern sei
7. Eine Oraza an den Freund eines Freundes, um uns Wein zu bringen
8. Ich habe an der Toilette vorbei geschrieben, da es zwei davon gab – ich habe die falsche gewählt und bin dann gefallen
9. fiel aus der Badewanne

Ich rannte einmal mit einem Messer hinter meinem Mann durch die Wohnung, obwohl ich ein paar Gläser Champagner getrunken hatte. Am nächsten Morgen wurde es unheimlich – und plötzlich hätte ich mit einem Messer aufgehört, aber ich beschloss einfach, Angst zu machen. Und ich weiß nicht, warum ich so einen Sprung auf mich fand!

Ständig das Gleiche, wie ich mich betrinke, ich in den Park der Wichser gehe, um etwas zu suchen, mit dem ich mich über sie lustig machen kann, oder ich erstelle diese Themen im Forum ... am Morgen denke ich, bin ich nicht ein Idiot? ...

Irgendwie klebte ein Typ an mir, und ich war so betrunken, dass ich anfing, ihm im Volksmund zu erklären, man sagt, nichts wird brechen, weil ich eine „Bloody Mary“ bin (es gab sie) und diese Hysterie so tief in meine Seele eingedrungen ist dass ich fast jedem, den ich traf, zurief: „Ich bin eine Bloody Mary“, zum Glück war das nicht in meiner Heimatstadt

- * rief den ersteren an, drückte alles aus, was ich über ihn denke
*Angerufener Geliebter, sagte, wie ich ihn will
*Döner mit Folie gegessen
* beschimpfte den Typen, den ich im Club getroffen hatte, obwohl er mir half, mir etwas Wasser brachte
*hat in einem Club bei einem Wettbewerb einen Striptease getanzt und den zweiten Platz erreicht
*wirft Eis auf den Fremden
* Der Freund meines Mannes fährt einen gelben Hamer. So jemanden habe ich in Korea noch nie gesehen. als wir alle zusammen abhängen gingen. Ich beugte mich aus dem Auto meines Mannes, zeigte auf den fahrenden Hammer vor mir und schrie, dass dieses Auto mein Freund sei
*Gestern war ich im Club. Als ich morgens mit dem Taxi nach Hause fuhr, sagte ich zum Fahrer: [aus dem Koreanischen übersetzt. wörtlich!] „Das Essen, das ich gerade gegessen habe, hat mir gesagt, dass es raus will!“
*Ich habe auch einen mongolischen Freund. Ich kletterte auf seinen Rücken, ließ mich auf seinem Rücken tragen und schrie auf der ganzen Straße, dass er mein mongolisches Pferd sei
und es gab noch so viel mehr, an das du dich nicht erinnern kannst ...

Ich habe dem Kerl um 4 Uhr morgens geschrieben. Gute Nacht, Teuer"

Wir betranken uns mit Brandy-Freunden, alle gingen nach Hause, und ich rief ein Taxi (es war 3 Uhr morgens) und ging zu meinem Ex-Freund, mit dem ich vor 4 Monaten Schluss gemacht hatte (der Freunde geblieben ist). Ich weiß nicht mehr, wie es mir ergangen ist Ich betrat den Eingang, gelangte zu seiner Wohnung, brach in seine Tür ein und schrie „MARIT ME MARAT“, der arme Ohrenel. Er schleppte mich nach Hause und stellte mich unter eine kalte Dusche, gab mir starken Tee. Versöhnt und sind immer noch zusammen. Danach trinke ich kein Glas Champagner mehr.


...

02.10.2011, 22:09

Das Opfer ging mit einem Mann durch den Garten, und dann schien es mir, dass er mich irgendwie beleidigte, indem er ein paar Schritte vor mir ging und nicht neben mir. Ich war beleidigt und kletterte auf einen Baum, aber er bemerkte es nicht ... er rannte anderthalb Stunden durch den Garten und suchte nach mir ... und ich wurde ruhig auf einem Baum ohnmächtig und schlief bis zum Morgen . ...
...
Aber am Morgen konnte ich mich nicht sofort erinnern, wie ich auf den Zweigen gelandet war. Sty-yyyyy-unten, wie es danach war
;D;D;D

Deutung

02.10.2011, 22:42

Ich schäme mich für manche Taten, die ich begehe, während ich nüchtern bin :) Aber das ist näher an der Philosophie. Während ich betrunken war ... Es hat viel Spaß gemacht, ich habe mich geschämt ... nein, tut mir leid)))))

Elena Lotus

02.10.2011, 23:17

Als mir gestern klar wurde, dass mein Telefon (OOO!!!) jetzt nicht mehr meins ist, habe ich mich betrunken. sehr. ein Geheimnis, und dann werde ich darüber nachdenken, wem ich es erzählen kann ... Das Restaurant Paberty war erneut schockiert. Jetzt schaue ich mir die Fotogalerie an, in der Hoffnung zu sehen, was passiert ist: (aber schäme dich nicht ... nein ... ich dachte nur, dass ich anständig bin.

02.10.2011, 23:31

;D;D;D
Ich habe immer argumentiert, dass Tanten nicht trinken sollten!!! ALLE!!! ;)

..;D;D;D Du sprichst die Wahrheit

02.10.2011, 23:36

Eine betrunkene Frau ist wie eine chinesische Daunenjacke: weich und federnd.
Galygin

Elena Lotus

02.10.2011, 23:41

Und Männer mögen ja? Jeder kann trinken. und Tanten und Onkel ... da muss man nur aufpassen ... heute tut der Kopf nicht weh ... die Seele tut weh ... sich betrinken? Nur ein Teufelskreis ;)

03.10.2011, 00:15

Trink alles und jedes, solange du jung und gesund bist :)

03.10.2011, 01:48

gezielt aus dem Frauenforum geklaut :)

Ich hätte fast in den Wäschekorb gepinkelt, vor den Augen meiner Mutter ..... verwechselt mit der Toilette .... ups ....

Das Opfer ging mit einem Mann durch den Garten, und dann schien es mir, dass er mich irgendwie beleidigte, indem er ein paar Schritte vor mir ging und nicht neben mir. Ich war beleidigt und kletterte auf einen Baum, aber er bemerkte es nicht ... er rannte anderthalb Stunden durch den Garten und suchte nach mir ... und ich wurde ruhig auf einem Baum ohnmächtig und schlief bis zum Morgen . ...
...
Aber am Morgen konnte ich mich nicht sofort erinnern, wie ich auf den Zweigen gelandet war. Sty-yyyyy-unten, wie es danach war

Auf dem Balkon, in dem meine Mutter Zwiebeln angebaut hat, standen Becken und Töpfe. Ich habe „schwach“ in jeden dieser Töpfe gepisst =((((in meinen eigenen Betten ((Natürlich werde ich es meiner Mutter nicht sagen, wirf alles verdammt noch mal in die Müll, ich bin hier, ich habe beschlossen, auf dein Grün zu pissen! Nun, er wuchs weiter, dann ging er zum Salat

03.10.2011, 05:35

Wir betranken uns mit Brandy-Freunden, alle gingen nach Hause, und ich rief ein Taxi (es war 3 Uhr morgens) und ging zu meinem Ex-Freund, mit dem ich vor 4 Monaten Schluss gemacht hatte (der Freunde geblieben ist). Ich weiß nicht mehr, wie es mir ergangen ist Ich betrat den Eingang, gelangte zu seiner Wohnung, brach in seine Tür ein und schrie „MARIT ME MARAT“, der arme Ohrenel. Er schleppte mich nach Hause und stellte mich unter eine kalte Dusche, gab mir starken Tee. Versöhnt und sind immer noch zusammen. Danach trinke ich kein Glas Champagner mehr.

Das ist ganz schön wahre Begebenheit Liebe.
Und auch über die Vorteile der Trunkenheit.

(Trinkt, Mädchen, und das Glück wird zu euch kommen.)

HERZNEUROSE (KARDIOPHOBIE). Eine Sonderform der Phobie ist neben dem Paniksyndrom die Kardiophobie, die aufgrund ihrer charakteristischen Klinik und signifikanten Häufigkeit besonders beschrieben werden sollte. Sie kommt vor allem bei jungen Menschen, häufiger bei Männern, aber auch bei Kindern vor.

Paroxysmal Angstzustände, bei dem Patienten einen Herzstillstand und den Beginn des Todes befürchten, kann ohne die Anwesenheit von auftreten somatische Erkrankung. Zu Beginn des nächsten Anfalls treten Übelkeit, Schwindel, innere Unruhe, leichte Kompression des Herzens.

In vielen Fällen kommt es jedoch ohne Vorläufer zu einem schweren Anfall: starker Herzschlag, im ganzen Körper spürbar, einige nehmen zu Blutdruck, starkes Enge- und Engegefühl in der Herzgegend, Kurzatmigkeit, Schwitzen, Schwindel und Unwohlsein Ohnmacht(jedoch nicht Bewusstlosigkeit), Zittern am ganzen Körper und elementare Angst. Der Patient glaubt, dass sein Herz in einer Sekunde stehen bleibt und er tot umfällt. Es ist die Angst vor Selbstzerstörung und Tod. Mit großer Aufregung rennen die Patienten umher und betteln um Hilfe. Kommt es während einer Autofahrt zu einem Angstanfall, ist der Patient gezwungen, anzuhalten und sich auszuruhen.

Nach dem ersten Anfall kommt es zur phobischen Entwicklung. Kranke verlieren Seelenfrieden, lebe in ständiger Angst, Warten auf den nächsten Angriff oder Tod, Erleben der Angst vor Angst (Wartenangst, Phobie). Gleichzeitig ist weder die Botschaft des Therapeuten über normal Arbeit des Herzens, noch Überzeugung, dass frühere Angriffe keine Folgen hatten. Die Häufigkeit der Anfälle und die Abstände zwischen ihnen sind unregelmäßig. In regelmäßigen Abständen überwacht der Patient aufmerksam seine Herzfunktionen, kontrolliert den Puls und registriert kleinste Abweichungen. Zufällige Extrasystolen empfindet er als unbestreitbare Anzeichen einer Krankheit mit aussichtslosem Ausgang.

Patienten sind anderen gegenüber misstrauisch vegetative Manifestationen sowie bei leichten Schwankungen ihres Wohlbefindens. Die Patienten kümmern sich um sich selbst, trauen sich kaum noch zu Fuß, sind bestrebt, alle Belastungen, Sorgen und vor allem schwierigen Situationen auszuschalten, um einen Anfall zu verhindern (Vermeidungsverhalten). Anstelle der Angst vor dem Tod kommt es in vielen Fällen immer mehr zu Angst vor Angst und angstauslösenden Situationen.

ERSCHEINUNGSBEDINGUNGEN. Der Grund für den ersten kardiophoben Anfall ist oft ein akuter Konflikt und eine Überforderung, Trennung und Enttäuschung, eine Situation der Einsamkeit und Verlassenheit sowie die Erfahrung im Falle eines Herztodes eines nahestehenden Menschen.

Zu wissen, dass es immer zu einem Herztod kommen kann, auch bei jungen und gesunden Menschen, wird zu einem besorgniserregenden Faktor. Durch den intensiven Konsum von Kaffee und Nikotin kann dieser Prozess in Gang gesetzt werden. Der Anfang liegt oft in der Kindheit. Überwiegend verwöhnte und abhängige Kinder sind von einer ausgeprägten Abhängigkeit von der Mutter betroffen, die in vielerlei Hinsicht von ambivalenten Einstellungen geprägt ist: der Erwartung von Liebe einerseits und dem Wunsch nach Unabhängigkeit mit aggressiven Impulsen andererseits, mit widersprüchlichen Bindungsphantasien und Trennung. Besonders gefährlich sind solche Einstellungen bei Beziehungsabbrüchen, Trennungen und Enttäuschungen. Ein Kardiophobiker lebt oft in Angst vor einer Trennung, bevor er merkt, dass er sie will und Angst davor hat. Regelmäßig kommt es zu gemeinsamen Problemen mit den Eltern und Konflikten mit dem Partner.

BEHANDLUNG
Bringt im akuten Zustand die Anwesenheit eines Arztes und ein Gespräch mit ihm keine Besserung, sind Beruhigungsmittel oder Betablocker angezeigt. Wie andere Patienten mit Angstneurosen versuchen viele Photiker, sich mit Alkohol selbst zu behandeln; aber seine Wirkung ist unzureichend und die Gefahr einer Alkoholabhängigkeit ist groß. Die Pharmakotherapie ist nur ein Hilfsmittel, vor allem in akute Fälle, sowie die Initiale wirksames Mittel.

Psychotherapie ist der Schlüssel. Je früher es beginnt, desto besser. Untersuchung der Ursachen und Konfliktsituationen Unmittelbar nach den ersten kardiophoben Anfällen kann die nachfolgende phobische Entwicklung gestoppt werden. Spätere Behandlung schwierig durchzuführen und erfordert eine langfristige Psychotherapie.

Mit diesen und anderen Angststörungen besonders gezeigt Verhaltenstherapie(spannende Konfrontation, kognitive Therapie, Selbstbewusstseinstraining). Besonderheit Das Angstvermeidungstraining besteht darin, dass es nach einem Desensibilisierungsmodell (an die entsprechenden Bedingungen alltäglicher Situationen) arbeitet, und das Angstmanagementtraining – mit Hilfe des erzwungenen Eintauchens in eine phobische Situation (Flut) und der Bildung von Bewältigungsstrategien. Bei schweren Angststörungen klinische Behandlung Einsatz verschiedener psychotherapeutischer Modelle.

Es scheint, dass PHP-Entwickler selten Parallelität verwenden. Ich werde nicht über die Einfachheit von synchronem Code sprechen, Single-Threaded-Programmierung ist natürlich einfacher und klarer, aber manchmal kann ein kleiner Einsatz von Parallelität zu einer spürbaren Leistungssteigerung führen.

In diesem Artikel werfen wir einen Blick darauf, wie Multithreading in PHP mithilfe der pthreads-Erweiterung erreicht werden kann. Dazu ist die Installation einer ZTS-Version (Zend Thread Safety) von PHP 7.x sowie der installierten Erweiterung pthreads v3 erforderlich. (Zum Zeitpunkt des Verfassens dieses Artikels müssen Benutzer in PHP 7.1 vom Master-Zweig im pthreads-Repository installieren – siehe Drittanbieter-Erweiterung.)

Eine kleine Klarstellung: pthreads v2 ist für PHP 5.x und wird nicht mehr unterstützt, pthreads v3 ist für PHP 7.x und wird aktiv weiterentwickelt.

Kommen wir nach so einem Exkurs gleich zur Sache!

Erledigung einmaliger Aufgaben

Manchmal möchten Sie einmalige Aufgaben in einer Multithread-Methode verarbeiten (z. B. die Ausführung einer E/A-gebundenen Aufgabe). In solchen Fällen können Sie die Thread-Klasse verwenden, um einen neuen Thread zu erstellen und einige Verarbeitungen in einem separaten Thread auszuführen.

Zum Beispiel:

$task = neue Klasse erweitert Thread ( private $response; öffentliche Funktion run() ( $content = file_get_contents("http://google.com"); preg_match("~ (.+)~", $content, $matches); $this->response = $matches; ) ); $task->start() && $task->join(); var_dump($task->response); // string (6) „Google“

Hier ist die run-Methode unsere Verarbeitung, die innerhalb des neuen Threads ausgeführt wird. Wenn Thread::start aufgerufen wird, wird ein neuer Thread erzeugt und die run-Methode aufgerufen. Anschließend verbinden wir den erzeugten Thread wieder mit dem Hauptthread, indem wir Thread::join aufrufen, der blockiert, bis die Ausführung des erzeugten Threads abgeschlossen ist. Dadurch wird sichergestellt, dass die Ausführung der Aufgabe abgeschlossen ist, bevor wir versuchen, das Ergebnis auszugeben (das in $task->response gespeichert ist).

Es ist möglicherweise nicht wünschenswert, eine Klasse mit zusätzlichen Verantwortlichkeiten im Zusammenhang mit der Thread-Logik zu belasten (einschließlich der Verantwortung für die Definition einer Ausführungsmethode). Wir können solche Klassen isolieren, indem wir sie von der Threaded-Klasse ableiten. Dann können sie in einem anderen Thread ausgeführt werden:

Klasse Task erweitert Threaded ( public $response; public function someWork() ( $content = file_get_contents("http://google.com"); preg_match("~ (.+) ~", $content, $matches); $ this->response = $matches; ) ) $task = new Task; $thread = new class($task) erweitert Thread ( private $task; öffentliche Funktion __construct(Threaded $task) ( $this->task = $task; ) öffentliche Funktion run() ( $this->task->someWork( ); ) ); $thread->start() && $thread->join(); var_dump($task->response);

Jede Klasse, die in einem separaten Thread ausgeführt werden muss, muss erbt von der Threaded-Klasse. Dies liegt daran, dass es die notwendigen Fähigkeiten zur Durchführung der Verarbeitung in verschiedenen Threads sowie implizite Sicherheit und nützliche Schnittstellen (z. B. Ressourcensynchronisierung) bietet.

Werfen wir einen Blick auf die Klassenhierarchie, die von der pthreads-Erweiterung bereitgestellt wird:

Threaded (implementiert durchquerbaren, sammelbaren) Thread Worker Volatile Pool

Wir haben die Grundlagen der Thread- und Threaded-Klassen bereits behandelt und erlernt. Werfen wir nun einen Blick auf die anderen drei (Worker, Volatile und Pool).

Thread-Wiederverwendung

Das Starten eines neuen Threads für jede Aufgabe, die parallelisiert werden muss, ist recht kostspielig. Dies liegt daran, dass die „Nothing-Common“-Architektur in pthreads implementiert werden muss, um Multithreading innerhalb von PHP zu erreichen. Das bedeutet, dass der gesamte Ausführungskontext der aktuellen Instanz des PHP-Interpreters (einschließlich aller Klassen, Schnittstellen, Merkmale und Funktionen) für jeden erstellten Thread kopiert werden muss. Da dies spürbare Auswirkungen auf die Leistung hat, sollte ein Thread nach Möglichkeit immer wiederverwendet werden. Threads können auf zwei Arten wiederverwendet werden: mit Worker s oder mit Pool s.

Die Worker-Klasse wird verwendet, um eine Reihe von Aufgaben synchron innerhalb eines anderen Threads auszuführen. Dies geschieht durch das Erstellen einer neuen Instanz des Workers (wodurch ein neuer Thread erstellt wird) und das anschließende Verschieben von Aufgaben auf den Stapel dieses einzelnen Threads (mithilfe von Worker::stack).

Hier ein kleines Beispiel:

Klasse Task erweitert Threaded ( private $value; public function __construct(int $i) ( $this->value = $i; ) public function run() ( usleep(250000); echo "Task: ($this->value) \n"; ) ) $worker = new Worker(); $worker->start(); for ($i = 0; $i stack(new Task($i)); ) while ($worker->collect()); $worker->shutdown();

Im obigen Beispiel werden 15 Aufgaben für ein neues $worker-Objekt über die Worker::stack-Methode auf den Stapel verschoben und dann in der Reihenfolge verarbeitet, in der sie übertragen wurden. Die oben gezeigte Worker::collect-Methode wird verwendet, um Aufgaben zu bereinigen, sobald ihre Ausführung abgeschlossen ist. Damit blockieren wir innerhalb der while-Schleife den Hauptthread, bis alle Aufgaben auf dem Stapel abgeschlossen und gelöscht sind – bevor wir Worker::shutdown aufrufen. Das vorzeitige Beenden eines Workers (d. h. solange noch Aufgaben erledigt werden müssen) blockiert weiterhin den Hauptthread, bis alle Aufgaben ihre Ausführung abgeschlossen haben. Die Aufgaben werden jedoch nicht durch Garbage Collection erfasst (was zu Speicherlecks führt).

Die Worker-Klasse stellt mehrere andere Methoden im Zusammenhang mit ihrem Aufgabenstapel bereit, darunter Worker::unstack zum Entfernen der zuletzt eingefügten Aufgabe und Worker::getStacked zum Abrufen der Anzahl der Aufgaben im Ausführungsstapel. Der Stapel des Arbeiters enthält nur Aufgaben, die erledigt werden müssen. Sobald eine Aufgabe auf dem Stapel abgeschlossen ist, wird sie entfernt und auf einem separaten (internen) Stapel zur Speicherbereinigung abgelegt (mithilfe der Methode Worker::collect).

Eine andere Möglichkeit, einen Thread für viele Aufgaben wiederzuverwenden, ist die Verwendung eines Thread-Pools (über die Pool-Klasse). Der Thread-Pool verwendet eine Gruppe von Workern, um die Ausführung von Aufgaben zu ermöglichen gleichzeitig, in dem der Parallelitätsfaktor (die Anzahl der Pool-Threads, auf denen er ausgeführt wird) beim Erstellen des Pools festgelegt wird.

Passen wir das obige Beispiel an, um einen Pool von Arbeitern zu verwenden:

Klasse Task erweitert Threaded ( private $value; public function __construct(int $i) ( $this->value = $i; ) public function run() ( usleep(250000); echo "Task: ($this->value) \n"; ) ) $pool = new Pool(4); for ($i = 0; $i subscribe(new Task($i)); ) while ($pool->collect()); $pool->shutdown();

Es gibt einige bemerkenswerte Unterschiede bei der Verwendung eines Pools im Gegensatz zu einem Worker. Erstens muss der Pool nicht manuell gestartet werden, sondern beginnt mit der Ausführung von Aufgaben, sobald diese verfügbar sind. Zweitens: wir schicken Aufgaben an den Pool, nicht Lege sie auf einen Stapel. Außerdem erbt die Pool-Klasse nicht von Threaded und kann daher nicht an andere Threads übergeben werden (im Gegensatz zu Worker).

Als bewährte Vorgehensweise sollten Arbeiter und Pools ihre Aufgaben stets bereinigen, sobald sie abgeschlossen sind, und sie dann selbst manuell beenden. Threads, die mit der Thread-Klasse erstellt wurden, müssen auch an den übergeordneten Thread angehängt werden.

pthreads und (nicht) Veränderlichkeit

Die letzte Klasse, die wir ansprechen werden, ist Volatile , eine neue Ergänzung zu pthreads v3. Der Begriff der Unveränderlichkeit ist zu einem wichtigen Konzept in pthreads geworden, da ohne ihn die Leistung erheblich sinkt. Daher sind die Eigenschaften von Threaded-Klassen, die selbst Threaded-Objekte sind, jetzt standardmäßig unveränderlich und können daher nach ihrer ursprünglichen Zuweisung nicht überschrieben werden. Die explizite Veränderbarkeit solcher Eigenschaften wird derzeit bevorzugt und kann mit der neuen Volatile-Klasse weiterhin erreicht werden.

Schauen wir uns ein Beispiel an, das die neuen Unveränderlichkeitsbeschränkungen demonstriert:

Klassenaufgabe erweitert Threaded // eine Threaded-Klasse ( öffentliche Funktion __construct() ( $this->data = new Threaded(); // $this->data ist nicht überschreibbar, da es eine Threaded-Eigenschaft einer Threaded-Klasse ist) ) $task = new class(new Task()) erweitert Thread ( // eine Threaded-Klasse, da Thread Threaded erweitert öffentliche Funktion __construct($tm) ( $this->threadedMember = $tm; var_dump($this->threadedMember-> data); // object(Threaded)#3 (0) () $this->threadedMember = new StdClass(); // ungültig, da die Eigenschaft ein Threaded-Mitglied einer Threaded-Klasse ist ) );

Die Threaded-Eigenschaften der Volatile-Klassen hingegen sind veränderbar:

Klasse Task erweitert Volatile ( öffentliche Funktion __construct() ( $this->data = new Threaded(); $this->data = new StdClass(); // gültig, da wir uns in einer flüchtigen Klasse befinden ) ) $task = new class(new Task()) erweitert Thread ( public function __construct($vm) ( $this->volatileMember = $vm; var_dump($this->volatileMember->data); // object(stdClass)#4 (0) () // immer noch ungültig, da Volatile Threaded erweitert, sodass die Eigenschaft immer noch ein Threaded-Mitglied einer Threaded-Klasse ist $this->volatileMember = new StdClass(); ) );

Wir sehen, dass die Volatile-Klasse die von der Threaded-Elternklasse auferlegte Unveränderlichkeit außer Kraft setzt, um die Möglichkeit zu bieten, die Threaded-Eigenschaften (sowie unset() ) zu ändern.

Es gibt noch ein weiteres Thema zu besprechen, das sich mit dem Thema Veränderlichkeit und der Volatile-Klasse befasst – Arrays. In pthreads werden Arrays automatisch in flüchtige Objekte umgewandelt, wenn sie einer Eigenschaft der Threaded-Klasse zugewiesen werden. Dies liegt daran, dass es einfach unsicher ist, ein Array aus mehreren PHP-Kontexten zu manipulieren.

Schauen wir uns das Beispiel noch einmal an, um einige Dinge besser zu verstehen:

$array = ; $task = new class($array) erweitert Thread ( private $data; öffentliche Funktion __construct(array $array) ( $this->data = $array; ) öffentliche Funktion run() ( $this->data = 4; $ this->data = 5; print_r($this->data); ) ); $task->start() && $task->join(); /* Ausgabe: Flüchtiges Objekt ( => 1 => 2 => 3 => 4 => 5) */

Wir sehen, dass flüchtige Objekte wie Arrays behandelt werden können, da sie Array-Operationen wie (wie oben gezeigt) den Teilmengenoperator () unterstützen. Allerdings unterstützen die Volatile-Klassen keine grundlegenden Array-Funktionen wie array_pop und array_shift . Stattdessen stellt uns die Threaded-Klasse ähnliche Operationen wie integrierte Methoden zur Verfügung.

Als Demo:

$data = neue Klasse erweitert Volatile ( public $a = 1; public $b = 2; public $c = 3; ); var_dump($data); var_dump($data->pop()); var_dump($data->shift()); var_dump($data); /* Ausgabe: object( [email protected])#1 (3) ( ["a"]=> int(1) ["b"]=> int(2) ["c"]=> int(3) ) int(3) int(1) Objekt ( [email protected])#1 (1) ( ["b"]=> int(2) ) */

Weitere unterstützte Vorgänge sind Threaded::chunk und Threaded::merge .

Synchronisation

Im letzten Abschnitt dieses Artikels werden wir uns mit der Synchronisierung in Pthreads befassen. Bei der Synchronisierung handelt es sich um eine Methode, mit der Sie den Zugriff auf gemeinsam genutzte Ressourcen steuern können.

Lassen Sie uns beispielsweise einen einfachen Zähler implementieren:

$counter = neue Klasse erweitert Thread ( public $i = 0; public function run() ( for ($i = 0; $i i; ) ) ); $counter->start(); for ($i = 0; $i i; ) $counter->join(); var_dump($counter->i); // gibt eine Zahl von 10 bis 20 aus

Ohne den Einsatz von Synchronisation ist die Ausgabe nicht deterministisch. Mehrere Threads schreiben ohne kontrollierten Zugriff auf dieselbe Variable, was bedeutet, dass Aktualisierungen verloren gehen.

Beheben wir das Problem, sodass wir die korrekte Ausgabe von 20 erhalten, indem wir eine Synchronisierung hinzufügen:

$counter = neue Klasse erweitert Thread ( public $i = 0; public function run() ( $this->synchronized(function () ( for ($i = 0; $i i; ) )); ) ); $counter->start(); $counter->synchronized(function ($counter) ( for ($i = 0; $i i; ) ), $counter); $counter->join(); var_dump($counter->i); // int(20)

Synchronisierte Codeblöcke können auch über die Methoden Threaded::wait und Threaded::notify (oder Threaded::notifyAll) miteinander kommunizieren.

Hier ist ein alternatives Inkrement in zwei synchronisierten While-Schleifen:

$counter = neue Klasse erweitert Thread ( public $cond = 1; public function run() ( $this->synchronized(function () ( for ($i = 0; $i notify(); if ($this->cond === 1) ( $this->cond = 2; $this->wait(); ) ) )); ) ); $counter->start(); $counter->synchronized(function ($counter) ( if ($counter->cond !== 2) ( $counter->wait(); // warten, bis der andere zuerst startet) for ($i = 10; $i notify(); if ($counter->cond === 2) ( $counter->cond = 1; $counter->wait(); ) ) ), $counter); $counter->join(); /* Ausgabe: int(0) int(10) int(1) int(11) int(2) int(12) int(3) int(13) int(4) int(14) int(5) int( 15) int(6) int(16) int(7) int(17) int(8) int(18) int(9) int(19) */

Vielleicht bemerken Sie es zusätzliche Bedingungen, die um den Aufruf von Threaded::wait herum platziert wurden. Diese Bedingungen sind wichtig, da sie die Fortsetzung eines synchronisierten Rückrufs ermöglichen, wenn er eine Benachrichtigung erhalten hat und die angegebene Bedingung wahr ist. Dies ist wichtig, da Benachrichtigungen von anderen Orten als beim Aufruf von Threaded::notify kommen können. Wenn also Aufrufe der Threaded::wait-Methode nicht in Bedingungen eingeschlossen wären, würden wir sie ausführen falsche Weckrufe, was zu unvorhersehbarem Codeverhalten führt.

Abschluss

Wir haben uns die fünf Klassen im pthreads-Paket (Threaded, Thread, Worker, Volatile und Pool) und die Verwendung jeder Klasse angesehen. Wir haben uns auch das neue Konzept der Unveränderlichkeit in pthreads angeschaut Kurze Review Unterstützte Synchronisierungsfunktionen. Wenn diese Grundlagen vorhanden sind, können wir uns nun damit befassen, wie man Pthreads in realen Fällen verwendet! Dies wird das Thema unseres nächsten Beitrags sein.

Wenn Sie an der Übersetzung des nächsten Beitrags interessiert sind, lassen Sie es mich wissen: Kommentieren Sie den sozialen Bereich. Netzwerke, bewerten Sie den Beitrag und teilen Sie ihn mit Kollegen und Freunden.

Es gibt im Netz eine ganze Reihe von Lösungen, um Multithreading in PHP zu emulieren. Meistens basieren sie auf Forks, es gibt aber auch Variationen des Verwendungsthemas Locken, proc_open usw.

Aus dem einen oder anderen Grund passten alle Optionen, die mir zur Verfügung standen, nicht zu mir und ich musste meine eigene Lösung schreiben. Meine Anforderungen waren wie folgt:

  • Die Verwendung von Gabeln;
  • Synchroner Modus mit Beibehaltung der Schnittstelle bei Fehlen der notwendigen Erweiterungen;
  • Mehrfachverwendung von untergeordneten Prozessen;
  • Vollständiger Datenaustausch zwischen Prozessen. Diese. mit Argumenten ausführen und das Ergebnis erhalten, wenn es fertig ist;
  • Die Fähigkeit, während des Betriebs Ereignisse zwischen dem untergeordneten Prozess – „Thread“ – und dem Hauptprozess auszutauschen;
  • Arbeiten mit einem Thread-Pool unter Beibehaltung der Wiederverwendung, Weitergabe von Argumenten und Erhalten von Ergebnissen;
  • Umgang mit Laufzeitfehlern;
  • Timeouts für die Arbeitsausführung, Warten auf Arbeit durch einen Thread, Initialisierung;
  • Maximale Performance.

Das Ergebnis ist die AzaThread-Bibliothek (der alte Name ist CThread).

Beschreibung

AzaThread bietet eine einfache Schnittstelle zum Erstellen von Thread-Klassen. Die tatsächlich separate Prozesse für asynchrone Arbeit verwenden, aber Sie sollten sich darüber keine Sorgen machen. Sie können Ereignisse von einem Thread auslösen, Ergebnisse zurückgeben, denselben Thread mehrmals verwenden, indem Sie ihm Startargumente übergeben, oder einen Pool von 16 Threads erstellen, die Ihre Aufgaben wie warme Semmeln aufräumen, ohne darauf zu achten, dass die Arbeit erledigt wird in unterschiedlichen Prozessen.

Darüber hinaus können Sie die Leistung der Bibliothek problemlos testen verschiedene Modi, indem Sie die optimale Anzahl an Threads und die Möglichkeit der Datenübertragung zwischen Prozessen speziell für Ihre Konfiguration auswählen.

Für vollwertige Arbeit Folgende Erweiterungen sind erforderlich: libevent, Posix Und pcntl.

Die Bibliothek verwendet LibEvent und gepaarte Sockets, um zwischen Prozessen zu kommunizieren. Unterstützt 5 Optionen zur Datenübergabe (Argumente, Ergebnisse und Ereignisdaten)!

Ich gebe Optionen sofort mit Leistungsdaten an. Getestet mit einem Pool von acht Threads auf einem Intel Core i7 2600K 3,40 GHz (Ubuntu 11.04 auf einer virtuellen VMware-Maschine). Angegeben sind die durchschnittlichen Ergebnisse für 10 Testwiederholungen in jps (Jobs pro Sekunde – die Anzahl der Aufgaben, die einfach Argumente empfangen und Daten pro Sekunde liefern).

Die Erweiterung für die Arbeit mit Sockets wird automatisch ausgewählt. Sofern vorhanden, wird die Erweiterung verwendet Steckdosen, was zu einer Leistungsverbesserung führt. Ansonsten nutzt es Strom.

Der untergeordnete Prozess lauscht auf alle verfügbaren Signale. Standardmäßig folgt auf alle (außer SIGWINCH und SIGINFO) ein Herunterfahren. Dies kann jedoch leicht überschrieben werden, indem in der Thread-Klasse eine Methode mit dem Namen des Signals erstellt wird. Zum Beispiel sigWinch .

Im übergeordneten Prozess werden standardmäßig auch alle Signale abgefangen. Dies kann geändert werden, indem der Parameter listenMasterSignals der Klasse auf false gesetzt wird. In diesem Fall wird nur SIGCHLD verarbeitet. Sie können ganz einfach Ihre eigenen Handler hinzufügen, indem Sie eine statische Methode namens m erstellen<имя сигнала>. Zum Beispiel mSigTerm .

Wenn der untergeordnete Prozess aus irgendeinem Grund stirbt, wird die Klasse automatisch gegabelt, wenn eine neue Aufgabe gestartet wird. Es geschieht unmerklich und Sie müssen überhaupt nicht darüber nachdenken. Im Fehlerfall muss die Instanz lediglich nicht neu erstellt werden.

Der untergeordnete Prozess prüft regelmäßig, ob der übergeordnete Prozess vorhanden ist. Wenn es plötzlich stirbt, endet das Kind automatisch.

Alle von einem Thread oder Thread-Pool verwendeten Ressourcen werden automatisch bereinigt, wenn der Destruktor aufgerufen wird. Sie können jedoch durch Aufruf der Bereinigungsmethode zwangsweise bereinigt werden. In diesem Fall kann der Thread/Pool nicht mehr verwendet werden.

Bei Standardeinstellungen wird der Thread vorab initialisiert, unmittelbar beim Erstellen der Klasse. Wenn Sie den prefork-Parameter auf false setzen, erfolgt die Verzweigung nur zum Zeitpunkt des Taskstarts.

Im Allgemeinen gibt es eine ganze Reihe anpassbarer Parameter. Ändern Sie den Namen des untergeordneten Prozesses nach der Verzweigung (pName-Parameter des Konstruktors), Timeout für die Dauer der Aufgabe (timeoutWork), Timeout für maximale Zeit Warten auf Aufgaben durch einen untergeordneten Prozess (timeoutMaxWait), Timeout vor der Initialisierung (timeoutInit), Puffergrößen zum Lesen von Sockets (pipeReadSize, pipeMasterReadSize). Sie können Multitasking für Threads deaktivieren (Multitasking). In diesem Fall bricht der untergeordnete Prozess jedes Mal ab, wenn die Aufgabe abgeschlossen ist, und verzweigt sich für die nächste Ausführung erneut. Dadurch wird die Leistung deutlich reduziert.

Der Code ist mit Tests abgedeckt und ausführlich dokumentiert, Anwendungsbeispiele können in der Datei example.php eingesehen und ausgeführt werden. Komplexere Beispiele zur Fehlerbehandlung finden Sie im Unit-Test-Code.

Es gibt einen Debug-Modus, der sehr gute Ergebnisse liefert genaue Information darüber, was los ist und wo.

Anwendungsbeispiele

Das Hauptmerkmal ist maximale Einfachheit. Wenn Sie einfach etwas in einem separaten „Thread“ ausführen möchten, reicht der folgende Code aus:

Die Klasse „ExampleThread“ erweitert Thread (geschützte Funktion „process()“ (//Einige funktionieren hier)) $thread = new „ExampleThread();“ $thread->wait()->run();

Wenn alles vorhanden ist, was für eine vollwertige Arbeit erforderlich ist, wird die Aufgabe asynchron ausgeführt. Wenn nicht, funktioniert alles weiterhin, jedoch im synchronen Modus.

Mit der Übergabe eines Parameters und dem Erhalten eines Ergebnisses sieht der Code nur etwas komplizierter aus:

Die Klasse „ExampleThread“ erweitert Thread ( geschützte Funktion „process()“ ( return $this->getParam(0); ) ) $thread = new „ExampleThread();“ $thread->wait()->run(123); $result = $thread->wait()->getResult();

Ebenso fügen wir mit einer leichten Handbewegung die Ereignisbehandlung aus dem Thread hinzu:

Klasse BeispielThread erweitert Thread ( const EV_PROCESS = "process"; protected function process() ( $events = $this->getParam(0); for ($i = 0; $i trigger(self::EV_PROCESS, $event_data); ) ) ) // Zusätzliches Argument. $additionalArgument = 123; $thread->bind(ExampleThread::EV_PROCESS, function($event_name, $event_data, $additional_arg) ( // Ereignisverarbeitung), $additionalArgument); $events = 10; // Anzahl der Ereignisse, die der Thread generieren wird // Um ​​vor dem ersten Aufruf nicht manuell auf den Thread warten zu müssen, // können Sie die preforkWait-Eigenschaft in $thread->wait(); auf TRUE überschreiben. $thread = new BeispielThread(); $thread->run($events)->wait();

Und schließlich die Verwendung eines Pools von acht Threads mit Laufzeitfehlerbehandlung:

$threads = 8 // Anzahl der Threads $pool = new ThreadPool("ExampleThread", $threads); $num = 25; // Anzahl der Aufgaben $left = $num; // Anzahl der verbleibenden Aufgaben ( // Wenn es freie Threads im Pool gibt // Und wir noch Aufgaben ausführen müssen, während ($pool->hasWaiting() && $left > 0) ( // Beim Start erhalten wir die Thread-ID $threadId = $pool->run(); $left--; ) if ($results = $pool->wait($failed)) ( foreach ($results as $threadId => $result) ( / / Aufgabe erfolgreich abgeschlossen // Das Ergebnis kann // anhand der Thread-ID identifiziert werden ($threadId) $num--; ) ) if ($failed) ( // Behandlung von Laufzeitfehlern. // Der Job gilt als erfolglos // if der untergeordnete Prozess ist während der Ausführung gestorben oder // Timeout für die Aufgabenausführung ist abgelaufen foreach ($failed as $threadId) ( $left++; ) ) ) while ($num > 0); // Alle untergeordneten Prozesse beenden. Wir löschen die vom Pool verbrauchten Ressourcen. $pool->cleanup();

Ergebnisse des Leistungstests

Die Tests wurden auf zwei Maschinen mit Ubuntu 11.04 durchgeführt.
Der erste ist Intel Core i3 540 3,07 GHz.
Der zweite ist Intel Core i7 2600K 3,40 GHz (Ubuntu läuft auf einer virtuellen VMware-Maschine).

Ich gebe die Ergebnisse nur an, damit Sie die Produktivitätssteigerung beurteilen können. Auch hier handelt es sich um die durchschnittlichen Ergebnisse einer Serie von 10 Testwiederholungen in JPS (Jobs per Second – die Anzahl der Aufgaben pro Sekunde).

Als Aufgabe führen Threads den folgenden Müll aus:

Für ($i = 0; $i

Das erste Ergebnis gilt für den synchronen Betrieb (keine Gabelungen). Ich habe 18 und 20 Threads bei der ersten Konfiguration nicht ausprobiert, da die Leistung bereits bei 12 zu sinken begann.

Anzahl der Themen Erste Konfiguration Zweite
0 553 763
1 330 669
2 580 1254
4 1015 2188
8 1040 2618
10 1027 2719
12 970 2739
16 958 2904
18 - 2830
20 - 2730

Das heißt, die Leistung steigt je nach Prozessor um das 2- bis 4-fache oder mehr!

Der Code, der eine Reihe von Tests mit den erforderlichen Parametern ausführt, befindet sich in der Datei examples/speed_test.php. So können Sie ganz einfach die Leistung testen und die für Sie optimale Anzahl an Threads auswählen.

Ich würde mich sehr freuen, wenn die Bibliothek für jemanden nützlich ist. Alle Funktionswünsche oder entdeckten Fehler können auf Github hinterlassen werden. Ich werde die Bibliothek schnell beheben und verbessern.

Es gibt im Netz eine ganze Reihe von Lösungen, um Multithreading in PHP zu emulieren. Meistens basieren sie auf Forks, es gibt aber auch Variationen des Themas mit Curl, proc_open usw.

Aus dem einen oder anderen Grund passten nicht alle Optionen, die ich fand, zu mir und ich musste meine eigene Lösung schreiben.
Meine Anforderungen waren wie folgt:

  • Die Verwendung von Gabeln;
  • Synchroner Modus mit Beibehaltung der Schnittstelle bei Fehlen der notwendigen Erweiterungen;
  • Mehrfachverwendung von untergeordneten Prozessen;
  • Vollständiger Datenaustausch zwischen Prozessen. Diese. mit Argumenten ausführen und das Ergebnis erhalten, wenn es fertig ist;
  • Die Fähigkeit, während des Betriebs Ereignisse zwischen dem untergeordneten Prozess – „Thread“ – und dem Hauptprozess auszutauschen;
  • Arbeiten mit einem Thread-Pool unter Beibehaltung der Wiederverwendung, Weitergabe von Argumenten und Erhalten von Ergebnissen;
  • Umgang mit Laufzeitfehlern;
  • Timeouts für die Arbeitsausführung, Warten auf Arbeit durch einen Thread, Initialisierung;
  • Maximale Performance;
Das Ergebnis ist eine Bibliothek AzaThread(alter Name - CThread).

Für Ungeduldige hier der Link zur Quelle:
github.com/Anizoptera/AzaThread

Beschreibung

AzaThread bietet eine einfache Schnittstelle zum Erstellen von Thread-Klassen. Die tatsächlich separate Prozesse für asynchrone Arbeit verwenden, aber Sie sollten sich darüber keine Sorgen machen. Sie können Ereignisse von einem Thread senden, Ergebnisse zurückgeben, denselben Thread mehrmals verwenden, indem Sie ihm Startargumente übergeben, oder einen Pool von 16 Threads erstellen, die Ihre Aufgaben wie warme Semmeln aufräumen, ohne darauf zu achten, dass die Arbeit ausgeführt wird in unterschiedlichen Prozessen.

Darüber hinaus können Sie die Leistung der Bibliothek ganz einfach in verschiedenen Modi testen, indem Sie die optimale Anzahl an Threads und die Möglichkeit der Datenübertragung zwischen Prozessen speziell für Ihre Konfiguration auswählen.

Für die volle Funktionalität sind folgende Erweiterungen erforderlich: libevent, Posix Und pcntl.

Die Bibliothek verwendet LibEvent und gepaarte Sockets, um zwischen Prozessen zu kommunizieren. Unterstützt 5 Optionen zur Datenübergabe (Argumente, Ergebnisse und Ereignisdaten)!

Ich gebe Optionen sofort mit Leistungsdaten an. Getestet mit einem Pool von acht Threads auf einem Intel Core i7 2600K 3,40 GHz (Ubuntu 11.04 auf einer virtuellen VMware-Maschine). Angegeben sind die durchschnittlichen Ergebnisse für 10 Testwiederholungen in jps (Jobs pro Sekunde – die Anzahl der Aufgaben, die einfach Argumente empfangen und Daten pro Sekunde liefern).

Die Erweiterung für die Arbeit mit Sockets wird automatisch ausgewählt. Sofern vorhanden, wird die Erweiterung verwendet Steckdosen, was zu einer Leistungsverbesserung führt. Ansonsten nutzt es Strom.

Der untergeordnete Prozess lauscht auf alle verfügbaren Signale. Standardmäßig folgt auf alle (außer SIGWINCH und SIGINFO) ein Herunterfahren. Dies kann jedoch leicht überschrieben werden, indem in der Thread-Klasse eine Methode mit dem Namen des Signals erstellt wird. Zum Beispiel sigWinch.

Im übergeordneten Prozess werden standardmäßig auch alle Signale abgefangen. Dies kann durch Setzen des Klassenparameters geändert werden listenMasterSignals zu falsch. In diesem Fall wird nur SIGCHLD verarbeitet. Sie können ganz einfach Ihre eigenen Handler hinzufügen, indem Sie eine statische Methode namens erstellen M< имя сигнала > . Zum Beispiel mSigTerm.

Wenn der untergeordnete Prozess aus irgendeinem Grund stirbt, wird die Klasse automatisch gegabelt, wenn eine neue Aufgabe gestartet wird. Es geschieht unmerklich und Sie müssen überhaupt nicht darüber nachdenken. Im Fehlerfall muss die Instanz lediglich nicht neu erstellt werden.

Der untergeordnete Prozess prüft regelmäßig, ob der übergeordnete Prozess vorhanden ist. Wenn es plötzlich stirbt, endet das Kind automatisch.

Alle von einem Thread oder Thread-Pool verwendeten Ressourcen werden automatisch bereinigt, wenn der Destruktor aufgerufen wird. Sie können jedoch zwangsweise gelöscht werden, wenn Sie die Methode aufrufen Aufräumen. In diesem Fall kann der Thread/Pool nicht mehr verwendet werden.

Bei Standardeinstellungen wird der Thread vorab initialisiert, unmittelbar beim Erstellen der Klasse. Wenn Sie den Parameter festlegen Vorgabel auf „false“ gesetzt, dann wird die Verzweigung nur dann durchgeführt, wenn die Aufgabe gestartet wird.

Im Allgemeinen gibt es eine ganze Reihe anpassbarer Parameter. Ändern Sie den Namen des untergeordneten Prozesses nach fork (Parameter pName Konstruktor), Timeout für die Dauer der Aufgabe ( timeoutWork), Timeout für die maximale Wartezeit auf Aufgaben durch einen Kindprozess ( timeoutMaxWait), Timeout für die Vorinitialisierungszeit ( timeoutInit), Puffergrößen zum Lesen von Sockets ( pipeReadSize, pipeMasterReadSize).
Sie können Multitasking für Threads deaktivieren ( Multitasking). In diesem Fall bricht der untergeordnete Prozess jedes Mal ab, wenn die Aufgabe abgeschlossen ist, und verzweigt sich für die nächste Ausführung erneut. Dadurch wird die Leistung deutlich reduziert.

Der Code ist mit Tests abgedeckt und ausführlich dokumentiert, Anwendungsbeispiele können in der Datei eingesehen und ausgeführt werden example.php.
Komplexere Beispiele zur Fehlerbehandlung finden Sie im Unit-Test-Code.

Es gibt einen Debug-Modus, der sehr detaillierte Informationen darüber anzeigt, was genau und wo passiert.

Anwendungsbeispiele

Das Hauptmerkmal ist maximale Einfachheit. Wenn Sie einfach etwas in einem separaten „Thread“ ausführen möchten, reicht der folgende Code:
Klasse BeispielThread erweitert Thread (geschützte Funktion Prozess() ( // Einige funktionieren hier)) $thread = new BeispielThread(); $thread->wait()->run();
Wenn alles vorhanden ist, was für eine vollwertige Arbeit erforderlich ist, wird die Aufgabe asynchron ausgeführt. Wenn nicht, funktioniert alles weiterhin, jedoch im synchronen Modus.

Mit der Übergabe eines Parameters und dem Erhalten eines Ergebnisses sieht der Code etwas komplizierter aus:
Klasse BeispielThread erweitert Thread ( geschützte Funktion Prozess() ( return $this->getParam(0); ) ) $thread = new BeispielThread(); $thread->wait()->run(123); $result = $thread->wait()->getResult();

Auf ähnliche Weise fügen wir mit einer Handbewegung die Ereignisbehandlung aus dem Thread hinzu:
Klasse BeispielThread erweitert Thread ( const EV_PROCESS = "process"; protected function process() ( $events = $this->getParam(0); for ($i = 0; $i< $events; $i++) { $event_data = $i; $this->trigger(self::EV_PROCESS, $event_data); ) ) ) // Zusätzliches Argument. $additionalArgument = 123; $thread->bind(ExampleThread::EV_PROCESS, function($event_name, $event_data, $additional_arg) ( // Ereignisverarbeitung), $additionalArgument); $events = 10; // Anzahl der Ereignisse, die der Thread generieren wird // Um ​​vor dem ersten Aufruf nicht manuell auf den Thread warten zu müssen, // können Sie die preforkWait-Eigenschaft in $thread->wait(); auf TRUE überschreiben. $thread = new BeispielThread(); $thread->run($events)->wait();

Und schließlich die Verwendung eines Pools von acht Threads mit Laufzeitfehlerbehandlung:
$threads = 8 // Anzahl der Threads $pool = new ThreadPool("ExampleThread", $threads); $num = 25; // Anzahl der Aufgaben $left = $num; // Anzahl der verbleibenden Aufgaben ( // Wenn es freie Threads im Pool gibt // Und wir noch Aufgaben ausführen müssen, während ($pool->hasWaiting() && $left > 0) ( // Beim Start erhalten wir die Thread-ID $threadId = $pool->run(); $left--; ) if ($results = $pool->wait($failed)) ( foreach ($results as $threadId => $result) ( / / Aufgabe erfolgreich abgeschlossen // Das Ergebnis kann // anhand der Thread-ID identifiziert werden ($threadId) $num--; ) ) if ($failed) ( // Behandlung von Laufzeitfehlern. // Der Job gilt als erfolglos // if der untergeordnete Prozess ist während der Ausführung gestorben oder // Timeout für die Aufgabenausführung ist abgelaufen foreach ($failed as $threadId) ( $left++; ) ) ) while ($num > 0); // Alle untergeordneten Prozesse beenden. Wir löschen die vom Pool verbrauchten Ressourcen. $pool->cleanup();

Ergebnisse des Leistungstests

Die Tests wurden auf zwei Maschinen mit Ubuntu 11.04 durchgeführt.
Erstens - Intel Core i3 540 3,07 GHz
Der zweite ist Intel Core i7 2600K 3,40 GHz (Ubuntu läuft auf einer virtuellen VMware-Maschine)

Ich gebe die Ergebnisse nur an, damit Sie die Produktivitätssteigerung beurteilen können.
Auch hier handelt es sich um die durchschnittlichen Ergebnisse einer Serie von 10 Testwiederholungen in JPS (Jobs per Second – die Anzahl der Aufgaben pro Sekunde).

Als Aufgabe führen Threads den folgenden Müll aus:
für ($i = 0; $i< 1000; $i++) { $r = mt_rand(0, PHP_INT_MAX) * mt_rand(0, PHP_INT_MAX); }
Das erste Ergebnis gilt für den synchronen Betrieb (keine Gabelungen).
Ich habe 18 und 20 Threads bei der ersten Konfiguration nicht ausprobiert, da die Leistung bereits bei 12 zu sinken begann.

Anzahl der Themen Erste Konfiguration Zweite
0 553 763
1 330 669
2 580 1254
4 1015 2188
8 1040 2618
10 1027 2719
12 970 2739
16 958 2904
18 - 2830
20 - 2730

Das heißt, die Leistung steigt je nach Prozessor um das 2- bis 4-fache oder mehr!

Der Code, der eine Reihe von Tests mit den erforderlichen Parametern ausführt, befindet sich in der Datei Beispiele/speed_test.php. So können Sie ganz einfach die Leistung testen und die für Sie optimale Anzahl an Threads auswählen.