phpbar.de logo

Mailinglisten-Archive

[php] Schlafende Prozesse / flock() / ignore_user_abort() / file_get_contents()

[php] Schlafende Prozesse / flock() / ignore_user_abort() / file_get_contents()

Christian Grobmeier grobmeier at gmail.com
Fr Mär 19 23:45:29 CET 2010


>  > [...] Ich glaube, du solltest mal einen meiner Blogartikel lesen:
>  > http://www.grobmeier.de/2009/08/21/performance-ofnonblocking-write-to-files-via-php.html
>
> Naja, den dortigen Vorschlag
>
>     $fp = fopen($file, 'a+');
>     flock($fp, LOCK_UN);
>     while($count < $loop) {
>        if (flock($fp, LOCK_EX)) {
>           fwrite($fp, $text);
>        }
>        flock($fp, LOCK_UN);
>     }
>     fclose($fp);
>
> halte ich erstens für umständlich (wenn die Schreibzugriffe hinterein-
> ander erfolgen, warum nicht einmal sperren, dann alles schreiben, dann
> entsperren?)

weil du unter umständen ja auch zwischendurch was anderes von anderen
threads rausschreiben willst, ohne diese Ordnung einzuhalten (z.b. im
Falle logging).

> und zweitens für fehlerträchtig (was ist, wenn ein zweiter
> Prozess eine Zeile anhängt, aber der Dateizeiger des ersten Prozesses
> noch eine Zeile darüber steht und selbst eine Zeile schreiben will?).

flock wartet in dem fall, bis es einen lock erhält. erst dann liefert
es true zurück und läuft weiter

> Ohne das wiederholte Entsperren und Sperren ist das ja meiner ursprüng-
> lichen Anfrage ähnlich (bis auf ftruncate($fp, 0);), und mir ging es
> ja weniger um die Geschwindigkeitsdetails als vielmehr um das Sperren
> an sich.

http://php.net/manual/de/function.flock.php
"flock() erlaubt es Ihnen ein einfaches Leser/Schreiber Modell zu
erstellen, welches auf fast jeder Plattform benutzt werden kann"

Gruß,
Christian


>
>
> Am 16.03.2010 21:52 schrieb Dieter Schmidt:
>
>  > damit du nicht herumstochern musst, kann ich dir nur eines empfehlen,
>  > gehe der Sache wirklich auf den Grund. Ich würde an deiner Stelle eine
>  > Profiler installieren. [...]
>
> Nett gemeint, aber ich glaube, das kann ich als Kunde eines Webhosting-
> Anbieters nicht. Außerdem hat mich schon die Produktbeschreibung er-
> schlagen -- bis ich das kapiere, habe ich durch ein paar gut durch-
> dachte Änderungen vielleicht schon mehr gewonnen...
>
>
> Am 17.03.2010 20:48 schrieb Yannik Hampe:
>
>> [...] der schlafende Prozess hält noch Systemressourcen, wie zum
>> Beispiel Filelocks. Das kann andere Prozesse wiederrum blockieren.
>
> Ja, das ist meine Vermutung (leider nicht mehr als eine Vermutung).
>
>> [...] Wie viele Prozesse sammeln sich denn da an? 5? 10? 100? 1000?
>> Irgendwann werden auch schlafende Prozesse für das System zu Last,
>> wenn es nur genug sind. [...]
>
> Größenordnung bis zu 50 würde ich sagen.
>
>> Dateisperren werden auch dann freigegen, wenn man fclose() aufruft.
>> fclose() wird am Ende jedes Scripts von php für alle noch nicht
>> freigegeben Dateien automatisch aufgerufen.
>
> Gilt das auch für Skripte, die per Timeout beendet werden?
>
>> [...] Bedenke hier, das ftruncate() die Datei auf 0 Byte kürzt. Der
>> Dateipointer, der sich am Ende der Datei befindet bleibt von
>> ftruncate jedoch unberührt. Da du jedoch mit fputs wohl an den
>> Anfang der Datei schreiben möchtest, solltest du einmal rewind($fp);
>> ausführen.
>
> Ok, verstanden. Guter Tipp!
>
>> [...] Und ja, für Dateien zum lesen musst du auch sperren, aber dann
>> brauchst du keine exklusive Sperren, dann tut flock($fp, LOCK_SH).
>
> Ja, das hatte ich auch so verstanden und gemeint. Danke für die Be-
> stätigung.
>
>> [...] Bei file_put_content kannst du einen Parameter zum Sperren
>> mitgeben: file_put_contents("/some/path", "some data", LOCK_EX);
>> Leider habe ich keine Ahnung, wie file_get_contents intern
>> funktioniert und die Leute die sich in Foren dazu auslassen
>> spekulieren alle nur und haben keine Ahnung ;-). [...]
>
> Ok, dann werde ich auch die durch fopen() usw. ersetzen.
>
>> Woher weißt du denn, dass der Server hängt?
>
> Eine Suchanfrage (bei der vermutlich eine der Index-Dateien neu auf-
> gebaut werden muss, s. o.) führt zum "halben" Laden der Seite (eben
> bis zu der Ausgabe vor Neuaufbau der Index-Datei) und macht danach
> nicht weiter (keine weitere HTML-Ausgabe, Browser zeigt weiter "Lade
> Seite..." an). Vermutung: Prozess wartet "ewig" auf Freigabe zum
> Schreiben der Index-Datei.
>
>> Was ist das überhaupt für ein Server? Linux?
>
> Webhosting auf Linux-Server (x86_64).
>
>> Hast du ssh-Zugang drauf?
>
> Öh... Was ist das?
>
>> Meinst du er hängt, weil in deinem Browser nichts ankommt?
>
> So in etwa, s. o.
>
>> Oder weil du auf einer Konsole warst und gesehen hast, dass der
>> Prozessor auf 100% Auslastung steht?
>
> Nein, den Server bringe ich nicht in die Knie (zum Glück -- mit End-
> losschleifen habe ich das schon hinbekommen...).
>
>> [...] Untersuchen könntest du das in dem du alle deine flock-Aufrufe
>> durch so etwas erstzt:
>> flock($fp, LOCK_EX | LOCK_NB, $wouldblock);
>> if ($wouldblock) throw new Exception('Could not acquire lock for file ...');
>
> Naja, es soll ja durchaus zulässig sein, dass ein Prozess warten muss,
> bis er an die Reihe kommt.
>
>> Eine weitere Möglichkeit zur Fehlersuche sind debugger. [...] in dem
>> du die entsprechende option in der php.ini [...]  Dann spuckt dir
>> xdebug bei jeder Anfrage eine Datei aus (in das ebenfalls in der
>> php.ini eingestellte Verzeichnis. Normalerweise /tmp) [...]
>
> Ich weiß nicht, ob ich a) die nötigen Zugriffsrechte dafür habe und
> b) verstehe, was mir der Debugger mitteilt.
>
>> [...] Wenn der Fehler nur bei jedem hundertsten Aufruf zum Fehler
>> führt, dann ist das allerdings doch ein sehr frustrierende
>> Angelegenheit. Genau wie die Methode mit dem profiler [...]
>
> Und so in etwa dürfte es sein, vielleicht ist die Zahl sogar noch
> größer.
>
>
> Alles in allem gab es ja das eine oder andere ermutigende Wort, die
> flock()-Funktion so einzusetzen, wie ich das vorhatte (nun ergänzt um
> die rewind()-Funktion). Daran werde ich mich nun begeben.
>
> Außerdem hatte ich noch eine andere Idee: Da ich (aus purer Faulheit,
> eine Funktion zu entwickeln, die nach Änderung im Datenbestand die
> bestehende Index-Datei an der richtigen Stelle geraderückt) bei Daten-
> änderung die Index-Datei verwerfe und bei der nächsten Suchanfrage neu
> aufbaue, kann es bisher zu folgender Situation kommen: Anfrage A löst
> Neuaufbau aus und sperrt währenddessen die Index-Datei, Anfrage B
> stellt ebenfalls fest, dass die Index-Datei neu aufgebaut werden muss
> und wartet auf Freigabe der Sperre -- um dann die Index-Datei eben-
> falls neu aufzubauen. Währenddessen kommt Anfrage C usw. Ich kann mir
> vorstellen, dass dieses wenig durchdachte Prinzip zu einem Dateisperre-
> Stau führen kann und habe es nun dahingehend abgewandelt, dass nach
> Erhalt der Sperre die Bedingung für Neuaufbau nochmals überprüft wird.
> Falls der Index gerade neu erzeugt wurde und keine Änderung in der
> Zwischenzeit den Index als überholt deklassiert, biege ich vor
> ftruncate() wieder ab, baue die Index-Datei nicht wieder auf und gebe
> die Sperre gleich wieder frei.
>
> Mal schauen, ob es mit diesen Änderungen besser wird.
>
> Eine Frage bleibt für mich aber trotzdem offen: Wieso hat es bei dem
> oben beschriebenen "Hängenbleiben" nicht geholfen, die Seite neu zu
> laden, wenn es geholfen hat, erst das Session-Cookie im Browser zu
> löschen und dann die Seite neu zu laden? Teilt mir der Server keinen
> neuen Prozess zu, wenn er über die Session-ID feststellt, dass ich
> schon einen Prozess (oder mehrere) laufen habe? Ich kann mir nicht
> vorstellen, dass den Server die Session-IDs interessieren, aber woran
> kann es sonst liegen?
>
> Nochmals vielen Dank an alle, die mir geantwortet haben!
>
> Mario Haßler
> --
> ** Allgemeine deutschsprachige PHP-Liste: php at phpbar.de **
> Informationen: http://www.phpbar.de
> http://lists.phpbar.de/mailman/listinfo/php
>

php::bar PHP Wiki   -   Listenarchive