2012-04-02 3 views
29

Wenn Sie lernen möchten wie Perl-Interpreter-Threads zu verwenden, gibt es gute Dokumentation in perlthrtut (threads tutorial) und the threads pragma manpage. Es ist definitiv gut genug, um ein paar einfache Skripte zu schreiben.Anwendungsfälle für Ithreads (Interpreter-Threads) in Perl und Gründe dafür, sie zu verwenden oder nicht?

Allerdings habe ich wenig Anleitung im Web auf warum und was Perl sinnvoll nutzen Interpreter gefunden Fäden für. In der Tat wird nicht viel über sie geredet, und wenn Leute über sie sprechen, ist es ziemlich oft, Leute davon abzuhalten, sie zu verwenden.

Diese Fäden, zur Verfügung, wenn perl -V:useithreadsuseithreads='define'; und entfesselt durch use threads ist, sind auch ithreads, und vielleicht mehr in geeigneter Weise genannt, um sie von Fäden sehr unterschiedlich sind, wie durch die Linux- oder Windows-Betriebssysteme oder die Java VM angeboten in dass standardmäßig nichts geteilt wird und stattdessen viele Daten kopiert werden, nicht nur der Thread-Stack, wodurch die Prozessgröße signifikant erhöht wird. (Um den Effekt zu sehen, einige Module in einem Testskript laden, dann Threads in einer Schleife erstellen für Tastendrücke Pause jedes Mal um und Speicher Anstieg des Task-Managers oder top sehen.)

[...] Bei jedem Start eines Threads werden alle Datenstrukturen in den neuen Thread nach kopiert. Und wenn ich alles sage, meine ich alle. Dies z.B. enthält Paketspeicher, globale Variablen, Lexika im Bereich. Alles!

- Things you need to know before programming Perl ithreads (Perlmonks 2003)

Wenn das Thema Perl ithreads forschen, werden Sie die Menschen sehen Sie von dessen Verwendung sie entmutigend ("extremely bad idea", "fundamentally flawed" oder "never use ithreads for anything").

The Perl thread tutorial highlights that "Perl Threads Are Different", aber es macht nicht viel Mühe zu erklären, wie sie unterschiedlich sind und was das für den Benutzer bedeutet.

Eine nützliche, aber sehr kurze Erklärung dessen, was itreads wirklich sind, ist from the Coro manpage under the heading WINDOWS PROCESS EMULATION. Der Autor dieses Moduls (Coro - der einzige echte Thread in Perl) rät auch davon ab, Perl-Interpreter-Threads zu verwenden.

Irgendwo habe ich gelesen, dass das Kompilieren von Perl mit aktivierten Threads zu einem wesentlich langsameren Interpreter führt.

Es gibt eine Perlmonks-Seite von 2003 (Things you need to know before programming Perl ithreads), in der der Autor fragt: "Jetzt magst du dich wundern, warum Perl ithreads nicht fork() verwendet hat? Hätte das nicht viel mehr Sinn ergeben?" Dies scheint vom Autor des forks Pragma geschrieben worden zu sein. Ich bin mir nicht sicher, ob die Informationen auf dieser Seite auch 2012 für neuere Perls gültig sind.

Hier sind einige Richtlinien für die Verwendung von Threads in Perl ich von meinen Lesungen destilliert haben (vielleicht fälschlicherweise so):

Bis jetzt meine Forschung. Nun, vielen Dank für mehr Licht können Sie sich auf dieses Thema von Perl in Perl werfen. Was sind einige sinnvolle Anwendungsfälle für Perl in Perl? Was ist der Grund dafür, sie zu benutzen oder nicht?

Antwort

21

Die kurze Antwort ist, dass sie ziemlich schwer sind (Sie können nicht mehr als 100 von ihnen billig starten), und sie zeigen unerwartetes Verhalten (etwas gemildert durch die jüngsten CPAN-Module).

Sie können sicher Perl ithreads verwenden, als unabhängige Akteure behandeln.

  1. Erstellen Sie einen Thread :: Warteschlange :: Any für "Arbeit".
  2. Starten Sie mehrere iThreads und "Ergebnis" -Warteschlangen, die ihnen die Warteschlangen ("Arbeit" + eigene "Ergebnis") durch Schließen übergeben.
  3. Laden (benötigen) den gesamten verbleibenden Code, den Ihre Anwendung benötigt (nicht vor Threads!)
  4. Fügen Sie Arbeit für die Threads in die Warteschlange wie erforderlich hinzu.

In "Arbeiter" ithreads:

  1. in jedem gemeinsamen Code bringen (für jede Art von Arbeit)
  2. Blocking-dequeue ein Stück Arbeit aus der Queue
  3. Bedarfs laden jede andere Abhängigkeiten, die für diese Arbeit erforderlich sind.
  4. Tun Sie die Arbeit.
  5. Übergeben Sie das Ergebnis über die Warteschlange "result" an den Hauptthread.
  6. Zurück zu 2.

Wenn einige „Arbeiter“ Threads beginnen ein wenig fleischig zu bekommen, und Sie müssen „Arbeiter“ Threads begrenzen, um eine Zahl dann neue an ihrer Stelle starten, dann erstellen " Launcher "thread first, dessen Aufgabe es ist," worker "-Threads zu starten und sie mit dem Hauptthread zu verbinden.

Was sind die Hauptprobleme mit Perl-Ithreads?

Sie sind ein wenig unpraktisch für "freigegebene" Daten, da Sie explizit die gemeinsame Nutzung tun müssen (kein großes Problem).

Sie müssen für das Verhalten von Objekten blicken mit Methoden zerstören, wie sie in einem Thread aus Anwendungsbereich gehen

der groß (wenn sie noch in einem anderen erforderlich sind!): Daten/Variablen die nicht explizit freigegeben sind CLONED in neue Threads. Dies ist ein Performance-Hit und wahrscheinlich gar nicht das, was Sie vorhaben. Die Arbeit besteht darin, iThreads aus einem ziemlich "unberührten" Zustand zu starten (nicht viele Module geladen).

IIRC, es gibt Module im Namensraum Threads ::, die dabei helfen, Abhängigkeiten explizit zu machen und/oder geklonte Daten für neue Threads zu bereinigen.

Auch, IIRC, gibt es ein etwas anderes Modell mit ithreads "Apartment" -Threads, implementiert von Thread :: Appartment, die ein anderes Nutzungsmuster und eine andere Reihe von Kompromissen hat.

Das Ergebnis:

Sie sie nicht verwenden, wenn Sie wissen, was Sie tun :-)

Fork auf Unix effizienter sein kann, aber die Geschichte IPC ist viel einfacher für Itreads. (Dies könnte durch CPAN-Module seit meinem letzten Blick gemildert worden sein :-)

Sie sind immer noch besser als Python-Threads.

Es könnte eines Tages sein, etwas viel besser in Perl 6.

+0

Danke! Dies ist die detaillierteste Gebrauchsanweisung für Perls Threads, die ich bisher gesehen habe. - In meiner Frage habe ich festgestellt, dass das * Wie * der Verwendung von E-Threads behandelt wird, während das * Warum * und * Was für * fehlen. Wenn man mehr darüber nachdenkt, ist das * wie *, das * warum * und das * was für * eng verwandt und tatsächlich ist das * wie * nicht genau genug (für gängige Perl-Benutzer wie mich), um das * warum zu beantworten * und * was für *. - Diese Antwort ist ein Schritt vorwärts. Danke noch einmal. – Lumi

+0

"Sie sind immer noch besser als Pythons Threads." - Kannst du das erklären? Bitte, es ist sehr interessant – nordicdyno

+3

Meistens geht es um die Python GIL in den meisten Implementierungen (überwiegend cpython, aber andere in geringerem Umfang). Im Grunde bedeutet dies, dass OS-Threads auf Python die CPU-Arbeit nicht gleichzeitig ausführen können - was den entscheidenden Punkt komplett zunichte macht. Sie können sie (Python-Threads) verwenden, um die I/O-Operationen etwas paralleler zu gestalten, aber dafür ist es einfacher, ereignisorientierte APIs zu verwenden. –

8

I "Themen" bei mehreren Gelegenheiten Perl verwendet haben. Sie sind am nützlichsten, um einen Prozess zu starten und mit etwas anderem fortzufahren. Ich habe nicht viel Erfahrung in der Theorie, wie sie unter der Haube arbeiten, aber ich habe eine Menge praktischer Programmiererfahrung mit ihnen.

Zum Beispiel habe ich einen Server-Thread, der eingehende Netzwerkverbindungen überwacht und eine Statusantwort ausspuckt, wenn jemand danach fragt. Ich erstelle diesen Thread, gehe dann weiter und erstelle einen weiteren Thread, der das System überwacht, fünf Elemente überprüft, ein paar Sekunden schläft und erneut eine Schleife erstellt. Es kann 3-4 Sekunden dauern, um die Überwachungsdaten zu sammeln, dann wird es in eine gemeinsam genutzte Variable geschoben, und der Server-Thread kann diese bei Bedarf lesen und sofort das letzte bekannte Ergebnis an jeden zurücksenden, der danach fragt. Wenn der Monitor-Thread feststellt, dass sich ein Element in einem schlechten Zustand befindet, startet er einen separaten Thread, um das Element zu reparieren. Dann geht es weiter, prüft die anderen Elemente, während das fehlerhafte repariert wird, und startet andere Threads für andere fehlerhafte Elemente oder fügt sich den fertigen Reparatur-Threads an. Das Hauptprogramm läuft alle paar Sekunden und stellt sicher, dass die Monitor- und Server-Threads nicht verbunden werden/noch laufen. All dies könnte als eine Reihe von separaten Programmen geschrieben werden, die eine andere Form von IPC verwenden, aber perls Threads machen es einfach.

Ein anderer Ort, wo ich sie verwendet habe, ist in einem Fraktalgenerator. Ich würde Teile des Bildes unter Verwendung irgendeines Algorithmus aufteilen und dann so viele Threads starten, wie ich CPUs habe, um die Arbeit zu machen. Sie würden ihre Ergebnisse in ein einzelnes GD-Objekt stopfen, das keine Probleme verursachte, weil sie jeweils an verschiedenen Teilen des Arrays arbeiteten, und wenn ich fertig war, würde ich das GD-Bild ausschreiben. Es war meine Einführung in Perl-Threads und war eine gute Einführung, aber dann habe ich es in C umgeschrieben und es war zwei Größenordnungen schneller :-). Dann schrieb ich meine Perl-Thread-Version um, um Inline :: C zu verwenden, und es war nur 20% langsamer als die reine C-Version. In den meisten Fällen, in denen Sie Threads aufgrund der CPU-Auslastung verwenden möchten, möchten Sie wahrscheinlich nur eine andere Sprache auswählen.

Wie bereits erwähnt, überschneiden sich Gabel und Gewinde für viele Zwecke. Coro erlaubt jedoch keine Multi-CPU-Nutzung oder parallele Verarbeitung wie zB Fork und Thread. Sie sehen Ihren Prozess immer nur zu 100%. Ich vereinfache dies zu sehr, aber ich denke, der einfachste Weg, Coro zu beschreiben, ist, dass es ein Scheduler für Ihre Subroutinen ist. Wenn Sie eine Subroutine haben, die blockiert, können Sie während der Wartezeit zu einer anderen springen und etwas anderes tun, beispielsweise wenn Sie eine App haben, die Ergebnisse berechnet und in eine Datei schreibt. Ein Block kann Ergebnisse berechnen und sie in einen Kanal schieben. Wenn es keine Arbeit mehr gibt, beginnt ein anderer Block sie auf die Festplatte zu schreiben. Während dieser Block auf der Festplatte wartet, kann der andere Block die Ergebnisse erneut berechnen, wenn er mehr Arbeit hat. Zugegeben, ich habe mit Coro nicht viel gemacht; es klingt nach einer guten Möglichkeit, einige Dinge zu beschleunigen, aber ich bin etwas deprimiert, weil ich nicht in der Lage bin, zwei Dinge gleichzeitig zu tun.

Meine persönliche Präferenz, wenn ich Multiprocessing machen möchte, ist die Verwendung von fork, wenn ich viele kleine oder kurze Dinge mache, Threads für eine Handvoll großer oder langlebiger Dinge.

Verwandte Themen