PHP Datei schreiben / Lesen gleichzeitig in 2 Prozessen

lordfritte

Lieutenant
Registriert
Juli 2006
Beiträge
965
Hallo ich habe folgendes vor: Ich möchte einen BackgroundWorker in PHP bauen(am liebten nur mit eigenen PHP Bordmitteln ohne, dass ich extra dazu was installieren muss). Dazu gibt es 2 Komponenten:
  1. Einen Ajax handler zum starten / stoppen und abfragen des Statutes.
  2. den eigentlichen Worker, welcher durch Ajax als eigener cli Prozess gestartet wird: shell_exec("php ... &");
der Worker soll regelmäßig in eine status Datei (als json, denn ich möchte mehr abfragen als nur läuft oder läuft nicht) schreiben
und über ajax möchte ich diese Datei lesen.

Das eigentlich Problem: ab und zu ließt ajax einen leeren String aus der Datei. Was ich mir wohl damit erkläre, dass schreiben und lesen gleichzeitig in der selben Datei nicht so gut ist?

Ich habe es auch schon mit flock versucht, aber ohne Erfolg. Wahrscheinlich muss ich wohl ein eigenes file locking mit einer extra lock-Datei basteln oder hat jemand eine andere Idee?
 
Hallo,
wenn 2 Threads gleichzeitig auf eine Ressource zugreifen, musst du diese synchronisieren damit diese nicht gleichzeitig auf der Ressource herumoperieren. Leider bin ich nicht tief genug in PHP drin um dir hier auf Sprachebene weiterhelfen zu können. Aber mal als Denkansatz...

greetz
hroessler
 
Hallo, das Problem ist: Es sind keine Threads sondern eigenständige Prozesse...
EDIT: Aber mit dem Stichwort "synchronisieren" habe ich trotzdem die richtige Lösung gefunden.
fopen mit der c statt w
Öffne Datei nur zum Schreiben. Wenn die Datei nicht existiert, wird diese erzeugt. Wenn sie existiert, wird sie weder gekürzt (im Gegensatz zu 'w'), noch schlägt der Aufruf dieser Funktion fehl (wie dies mit 'x' der Fall ist). Der Dateizeiger wird auf den Dateianfang platziert. Dies kann nützlich sein, wenn man eine "beratende" (kooperative) Sperre erhalten möchte (siehe flock()) bevor man versucht, die Datei zu ändern, da die Nutzung von 'w' die Datei kürzen könnte, bevor die Sperre erhalten wurde (falls Kürzen gewünscht ist, kann ftruncate() genutzt werden, nachdem die Sperre angefragt wurde).
 
  • Gefällt mir
Reaktionen: psYcho-edgE
Kommst dann um eine lock Datei nicht herum. Ist aber auch nicht so schwer umzusetzen.
 
Immer wenn mehrere Threads gleichzeitig auf was zugreifen sollen fällt mir der Begriff "Datenbank" ein :=)
Schreib den Status doch in eine einfache Tabelle mit nur einer Spalte und einer Zeile?
 
  • Gefällt mir
Reaktionen: psYcho-edgE
d2boxSteve schrieb:
Immer wenn mehrere Threads gleichzeitig auf was zugreifen sollen fällt mir der Begriff "Datenbank" ein :=)
Schreib den Status doch in eine einfache Tabelle mit nur einer Spalte und einer Zeile?

Die Frage ist wie performancelastig ist das mehrmals pro Sekunde in die Datenbank schreiben/lesen?
 
Mehrmals pro Sekunde? Wie oft ist das? 10 mal? 1000 mal?
Wie wäre es einfach mit ausprobieren? Sollte doch in 10 Minuten erledigt sein.

Ob du jetzt eine Lock Datei nimmst, oder einen Eintrag in einer Datenbank oooder dir einen dritten PHP Prozess hinstellst, der sich um die Synchonisation kümmert, macht keinen großen Unterschied.
 
Also eine Datenbank ist um ein vielfaches schneller als ein Dateisystem (wobei das von Dateisystem abhängt, einige mit Journaling sind ja quasi Datenbanken aber mit deutlich mehr Overhead).
Ich würde hier klar sowas wie MySQL/MariaDB (oder evtl PostgressSQL) vorziehen.
Ergänzung ()

Wenn der Cache in der Datenbank passend eingestellt ist passiert alles im RAM, und es gibt nix schnelleres :=)
 
  • Gefällt mir
Reaktionen: FranzvonAssisi
@d2boxSteve Für einen Lock reicht eine In-Memory DB. Da braucht's kein SQL. Selbst ein Key-Value Store ist eigentlich schon "zu viel", aber was kleineres wird man wohl kaum finden :D Hauptsache es gibt ein atomares "getAndset" oder "upsert" oder so.
 
benneque schrieb:
Mehrmals pro Sekunde? Wie oft ist das? 10 mal? 1000 mal?
Wie wäre es einfach mit ausprobieren? Sollte doch in 10 Minuten erledigt sein.

Ob du jetzt eine Lock Datei nimmst, oder einen Eintrag in einer Datenbank oooder dir einen dritten PHP Prozess hinstellst, der sich um die Synchonisation kümmert, macht keinen großen Unterschied.

naja vielleicht maximal 10 mal pro Sekunde, was aber sicher auch eine Lösung wäre ist redis. Aber mit fopen("c", ..) gibt es bis jetzt überhaupt keine Probleme
 
Du kannst auch Atomic Writes nutzen. Heißt: Du schreibst in Datei status.json.tmp und wenn alles fertig geschrieben ist, verschiebst du diese nach status.json. Der Verschiebevorgang ist dabei atomar, wird also in einem Befehl abgearbeitet, wodurch es nicht zu den angesprochenen Problemen kommen kann.
 
@Yuuri Dann sollte die Datei aber besser "status.json.tmp.[unique-id]" oder so heißen. Nicht, dass dann 2 Prozesse gleichzeitig da rein schreiben ;)
 
Über die eigentliche Implementierung hab ich jetzt extra nichts geschrieben. In PHP wäre das über tempnam() auch einfach über Dateien regelbar. Wobei je nach Komplexität ich auch den Weg über die DB vorziehen würde. Ich geh zumindest davon aus, dass sowieso bereits eine DB genutzt wird. Extra für diesen Zweck eine DB aufziehen ist allerdings vollkommen überzogen. Alternativ wäre auch ne lokale SQLite DB für den Zweck sinnvoll, so muss man keine extra DB hochziehen und PDO sollte sowieso verfügbar sein mit SQLite Treiber. Wobei man allerdings auch APC, memcache, shmop oder Semaphore in Betracht ziehen kann, insofern diese als Modul verfügbar sind.

Viele Möglichkeiten führen nach Rom, muss der TE sich nur eine Variante aussuchen und ein wenig probieren.
 
Zurück
Oben