Seite 1 von 1

Performance zwischen PHP und Python Crawler Scraper

Verfasst: Donnerstag 1. Juli 2021, 04:55
von MaschbauMichi
Hallo zusammen,

würdet Ihr mir bitte eine Frage zur Performance zwischen PHP und Python beantworten?

Es geht um einen Scraper oder Crawler, den ich mir mit PHP gebastelt habe. Da rufe ich eine URL auf und sauge mir den Quellcode bzw. den Inhalt daraus den ich habe möchte.

API hat leider nicht funktioniert bzw. brach ständig ab, sodass ich es auf diese Weise mache.

Leider dauert ein URL-Aufruf ca. 2 Sekunden. 10 URL-Aufrufe ca. 17 Sekunden und 100 URL-Aufrufe ca. 2,5 Minuten.
Das PHP-Skript läuft im Browser ab.

Bevor ich anfange Python zu lernen möchte ich fragen, ob es denn mit Python + CMD statt PHP + Browser schneller laufen würde, bei gleicher Internetgeschwindigkeit.

Danke.

Re: Performance zwischen PHP und Python Crawler Scraper

Verfasst: Donnerstag 1. Juli 2021, 08:44
von __deets__
Da läuft nix im Browser. Das läuft auf dem Server. Und grundsätzlich ist der limitierende Faktor hier die Webseite. An sich läuft hier also nix schneller oder langsamer. Eine Erhöhung der Geschwindigkeit erreicht man durch Parallelisierung. Das geht grundsätzlich sicher auch mit PHP, aber einfacher mit Python. So lange, bis die Webseite dich drosselt, weil du zu viel last erzeugst. Kann passieren. Muss aber nicht.

Re: Performance zwischen PHP und Python Crawler Scraper

Verfasst: Donnerstag 1. Juli 2021, 21:39
von LukeNukem
MaschbauMichi hat geschrieben: Donnerstag 1. Juli 2021, 04:55 würdet Ihr mir bitte eine Frage zur Performance zwischen PHP und Python beantworten?
Das ist, ehrlich gesagt, eine wirklich schwierige Frage, aber dazu weiter unten...
MaschbauMichi hat geschrieben: Donnerstag 1. Juli 2021, 04:55 API hat leider nicht funktioniert bzw. brach ständig ab, sodass ich es auf diese Weise mache.
Das kann an der API liegen. Oder an PHP. Oder an Deiner lokalen Konfiguration. Wenn ich mich recht entsinne, hat PHP da so konfigurierbare Speicher- und Laufzeitlimits. Das heißt: wenn Du sehr große Datenmengen abfragst, sie über eine langsame Verbindung lädtst oder der Server ein vielbeschäftigtes Kerlchen ist, dann kann es sein, daß Du in eines dieser Limits hineinläufst und der PHP-Interpreter Dein Skript hart beendet. Dazu könnten die Logdateien vielleicht zu Erkenntnissen führen.
MaschbauMichi hat geschrieben: Donnerstag 1. Juli 2021, 04:55 Das PHP-Skript läuft im Browser ab.
Ganz bestimmt nicht -- Du rufst mit dem Browser eine Webseite von einem (lokalen) Webserver ab, und der stößt dann Dein PHP-Skript an.
MaschbauMichi hat geschrieben: Donnerstag 1. Juli 2021, 04:55 Bevor ich anfange Python zu lernen möchte ich fragen, ob es denn mit Python + CMD statt PHP + Browser schneller laufen würde, bei gleicher Internetgeschwindigkeit.
Wie gesagt, das ist eine sehr schwierige Frage, weil dabei ungefähr drölfzigtausend Faktoren eine Rolle spielen.

Da ist zunächst die Frage, warum das die Geschichte lange dauert. Ist die Netzerkverbindung so lahm? Ist die Datenmenge so groß? Steht der Server unter einer hohen Last? Ist die Webseite sehr komplex und benötigt womöglich Daten aus einer stark belasteten Datenbank oder womöglich sogar aus aus externen Quellen (nein, nicht der Quatsch aus irgendwelchen CDNs etc...)? Oder ist die Webseite so umfangreich und / oder komplex, daß das Parsen sehr aufwändig ist?

Und dann... "ist Python schneller", naja, also... Für PHP gibt es (meines Wissens) nur einen Interpreter, für Python dagegen eine ganze Menge... und noch einen großen Haufen weiterer Möglichkeiten. Der Standard-Interpreter und die Referenzimplementierung von Python ist CPython, aber CPython ist nicht wirklich performanceoptimiert. Trotzdem war er früher einer der schnellsten Skriptspracheninterpreter am Markt, aber die anderen haben mittlerweile aufgeholt und CPython teilweise sogar überholt. PHP ist einer der Interpreter, die CPython mittlerweile sogar überholt haben, indem in den neueren Versionen viele massive Optimierungen eingebaut wurden, zum Beispiel indem viele (früher kostenpflichtige) Erweiterungen aus dem Zend-Universum eingebaut worden sind.

Aaaber es gibt da im Python-Universum ja noch eine ganze Menge mehr, zum Beispiel Pypy. Pypy kann, je nach Anwendungsfall und Implementierung, um Größenordnungen schneller als CPython, ich selbst habe schon Faktoren von vier bis über zehn gesehen. Und das ist dann am Ende wiederum deutlich schneller als der PHP-Interpreter... Es gibt aber auch noch andere Python-Interpreter, etwa den in Java entwickelten Interpreter Jython und das in .Net entwickelte IronPython, die nahtlos mit der Java- respektive .Net-Umgebung interagieren können -- dazu kann ich aber nicht viel sagen.

Weiterhin ist es so, daß es für Python etliche Möglichkeiten gibt, den Python-Sourcecode entweder in Maschinencode zu übersetzen -- zum Beispiel mit dem Compiler nuitka -- oder das nur für bestimmte Teile des Python-Code zu tun, etwa mit Numba. Zudem können performancekritische Teile des Code in C oder C++ implementiert und der so erzeugte Maschinencode einfach in Python integriert werden, für C++ etwa mit der Bibliothek Boost::Python. Für viele Python-Bibliotheken wie beispielsweise die bekannte Numpy-Bibliothek ist das der Fall; für Deinen Anwendungsfall (HTML parsen) ist der lxml-Parser bis zu zehn Mal so schnell als die reine Python-Implementierung html.parser.

Und dann ist da diese Sache mit der Parallelisierung, die der großartige __deets__ bereits erwähnt hat. PHP ist darauf ausgelegt, von einem Webserver ausgeführt zu werden, der viele Requests abarbeitet und jeden dieser Requests in einem eigenen Prozeß oder Thread ablaufen läßt, oder, anders gesagt: in PHP kümmert sich der Webserver um die Parallelisierung. Mittlerweile gibt es in PHP wohl eine Unterstützung für POSIX-Threads mit der Bibliothek pthreads und eine wohl etwas komfortablere und neuere Bibliothek "parallel" oä., und ich kenne beide nicht, aber im Vergleich dazu hat Python mit hochentwickelten und komfortablen Modulen wie threading und multiprocessing, sowie mit seinem modernen async-Framework zweifellos die Nase deutlich vorn, was die Benutzbarkeit angeht.

Nun, alle diese Ausführungen setzen nur einen Rahmen für meine wesentlichen Kernaussagen, und die beginnen mit den drei wichtigsten Kernprinzipien jeder Performanceoptimierung:

1. Premature optimization is the root of all evil. (Donald E. Knuth)
2. Measure, don't guess. (Kirk Pepperdine)
3. Make it work, make it right, make it fast. (Kent Beck)

Das heißt in der Praxis: irgendwelche "Standardrezepte" funktionieren nicht, sie machen Deinen Code nur weniger gut les- und damit optimierbar. Zweitens nutzt es nichts, eine Funktion zu optimieren, die nur einmal im Programm aufgerufen wird und eine Sekunde Laufzeit benötigt; viel sinnvoller ist es, eine Funktion zu optimieren, die nur eine Hundertstelsekunde Laufzeit verbraucht, dafür aber eintausend Mal aufgerufen wird, also muß man messen, wo die meiste Laufzeit verbraten wird, und genau dort ansetzen. Und genau deswegen ist der dritte Ansatz dann auch, erstmal zu schauen, daß das Programm überhaupt läuft, dann, daß es das Richtige tut, und erst zuletzt, wenn es das tut, mit der Performanceoptimierung zu beginnen. Alles andere ist Zeitverschwendung. Und, ach ja: ein bisschen Fachwissen über die betreffenden Technologien, die ihren zugrundeliegenden Implementierungen und ein bisschen Systemtechnik ist extrem sinnvoll und nützlich. ;-)

Nun, okay, nach diesen allgemeinen Ausführungen kommen wir dann mal zu Deinem konkreten Problem. Da Du uns darüber wenig bis keine detaillierten Informationen mitteilen möchtest (nebenbei bemerkt: bitte bedenke, daß es ein "Datenbankherstellerrecht" gibt und es womöglich nicht legal sein könnte, fremde Daten zu kopieren), muß ich leider ein bisschen ins Blaue schießen... Also, bei dem, was Du da machen möchtest, sehe ich im Kern zunächst zwei Punkte, die Deine langen Laufzeiten verursachen könnten: das Netzwerk einer- und das Parsen der Daten andererseits. Was davon wirklich das Teure ist, hängt von vielen Faktoren ab, und welcher der größere Faktor dabei ist, kannst Du nur durch konkrete Messungen herausfinden. Python ist dabei sicherlich nicht die schlechteste Sprache, zumal es -- wie oben erwähnt -- im Zweifelsfalls zumindest für den Parsing-Teil etliche Möglichkeiten bietet, die PHP vermutlich nicht hat. Was den Netzwerk-Teil angeht... da hilft vermutlich nur Parallelisierung, bis das Netzwerk saturiert ist, oder eine Verteilung. Verteilung? Ja, klar: wenn Du zwei oder drei Server hast, die sich in verschiedenen Netzwerken befinden und sich nicht alle denselben Upstream teilen, dann geht da natürlich noch mehr, in Python etwa mit Celery, Apache Storm oder Ähnlichem. Aber einen verteilten Cluster zu betreiben... ich frage mal so: wie groß ist der Zeit-, Lern-, Implementierungs- und Kostenaufwand, den Du Dir leisten kannst und willst? ;-)

Re: Performance zwischen PHP und Python Crawler Scraper

Verfasst: Samstag 3. Juli 2021, 16:17
von DeaD_EyE
MaschbauMichi hat geschrieben: Donnerstag 1. Juli 2021, 04:55 Leider dauert ein URL-Aufruf ca. 2 Sekunden. 10 URL-Aufrufe ca. 17 Sekunden und 100 URL-Aufrufe ca. 2,5 Minuten.
Der limitierende Faktor ist der antwortende Server, wo dein Programm die Daten abholt.
Wenn der Server zum Antworten 2 Sekunden braucht, dann ist das so und du kannst es auch nicht beschleunigen.

Die Dauer kannst du nicht verringern, aber die Anzahl der gleichzeitigen Verbindungen könntest du erhöhen.
Aber auch da muss ein limitierender Faktor gesetzt werden, um die Webserver nicht zu überlasten.

Ob du das mit Python, PHP, Ruby oder NodeJS machst, ist für den Prozess völlig egal.
Wie man das macht, ist abhängig von der Sprache und dem verwendeten Framework.

Bei Python würde ich jetzt z.B. asyncio in Verbindung mit queues, requests und Semaphoren arbeiten.

queues: Tasks einreihen
requests: Daten vom Webserver abholen (seit 2.0 auch support für asyncio)
Semaphore: Ressourcen limitieren (z.B. nur 10 gleichzeitige Verbindungen)
asyncio: Nur ein Thread, Nebenläufigkeit

Ob PHP Nebenläufigkeit unterstützt ist mir unbekannt, aber es würde mich wundern, falls nicht.

Re: Performance zwischen PHP und Python Crawler Scraper

Verfasst: Sonntag 4. Juli 2021, 04:32
von LukeNukem
DeaD_EyE hat geschrieben: Samstag 3. Juli 2021, 16:17 Bei Python würde ich jetzt z.B. asyncio in Verbindung mit queues, requests und Semaphoren arbeiten.
pydoc select

;-)