Warum beschleunigt Multithreading nicht das Parsen von HTML mit lxml?

9

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:

%Vor%

Die Ausgabe ist:

%Vor%

Genau das wollte ich! :)

    
Gregory Petukhov 29.08.2015, 11:20
quelle

2 Antworten

5

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.

%Vor%     
spectras 29.08.2015, 11:34
quelle
-1

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.

    
wa11a 29.08.2015 11:29
quelle