Ich versuche zu verstehen, warum das Ausführen mehrerer Parser in parallelen Threads das Parsen von HTML nicht beschleunigt. Ein Thread erledigt 100 Aufgaben doppelt so schnell wie zwei Threads mit jeweils 50 Aufgaben.
Hier ist mein Code:
%Vor%Ausgabe auf meiner CPU mit 4 Kernen:
%Vor%Laut FAQ ( Ссылка ) zwei Threads sollten schneller als ein Thread arbeiten.
Seit Version 1.1 gibt lxml die GIL (Pythons globale Interpretersperre) bei der Analyse von Festplatte und Arbeitsspeicher intern frei, solange Sie entweder den Standardparser (der für jeden Thread repliziert wird) oder einen Parser für jeden Thread selbst erstellen .
...
Je mehr Ihre XML-Verarbeitung in lxml verschoben wird, desto höher ist Ihr Gewinn. Wenn Ihre Anwendung durch XML-Parsing und -Serialisierung oder durch sehr selektive XPath-Ausdrücke und komplexe XSLTs gebunden ist, kann Ihre Beschleunigung auf Multiprozessor-Maschinen beträchtlich sein.
Die Frage ist also, warum zwei Threads langsamer sind als ein Thread?
Meine Umgebung: linux debian, lxml 3.3.5-1 + b1, gleiche Ergebnisse auf python2 und python3
BTW, mein Freund hat versucht, diesen Test auf Macos zu machen und bekam die gleiche Zeit für einen und zwei Threads. Wie auch immer, das ist nicht so, wie es laut Dokumentation sein sollte (zwei Threads sollten doppelt so schnell sein).
UPD: Danke an Spektren. Er wies darauf hin, dass es in jedem Thread einen Parser erstellen muss. Der aktualisierte Code der Funktion func
lautet:
Die Ausgabe ist:
%Vor%Genau das wollte ich! :)
Die Dokumentation gibt dort einen guten Hinweis: "Solange Sie entweder den Standardparser verwenden (der für jeden Thread repliziert wird) oder einen Parser für jeden Thread selbst erstellen."
Sie erstellen auf keinen Fall einen Parser für jeden Thread. Sie können sehen, dass die Funktion fromstring
verwendet wird, wenn Sie keinen Parser selbst angeben eine globale.
Nun zu der anderen Bedingung, können Sie am Ende der Datei sehen, dass html_parser
eine Unterklasse von lxml.etree.HTMLParser
ist. Ohne besonderes Verhalten und vor allem ohne lokalen Thread-Speicher. Ich kann hier nicht testen, aber ich würde glauben, dass Sie am Ende einen Parser über Ihre beiden Threads teilen, was nicht als "Standard-Parser" gilt.
Könnten Sie versuchen, die Parser selbst zu installieren und sie an fromstring
zu füttern? Oder ich werde es in einer Stunde oder so tun und diesen Beitrag aktualisieren.
Das liegt daran, wie Threads in Python funktionieren. Und es gibt Unterschiede zwischen Python 2.7 und Python 3. Wenn Sie das Parsen wirklich beschleunigen wollen, sollten Sie Multiprocessing und nicht Multithreading verwenden. Lesen Sie dies: Wie funktionieren Threads? in Python, und was sind häufige Python-Threading spezifischen Fallstricke?
Und hier geht es um Multiprozessing: Ссылка
Solange es keine io-Operationen sind, fügen Sie bei der Verwendung von Threads den Overhead der Kontextumschaltung hinzu, da immer nur ein Thread ausgeführt werden kann. Wann sind Python-Threads schnell?
Viel Glück.
Tags und Links python multithreading performance lxml gil