Wie arbeitet der PHP-Interpreter? Multitasking?

MC-René

Erfahrenes Mitglied
Hallo! ;)

Ich habe ein Programm lokal auf meinem PC welches bei Ereignis "X" eine php-Seite per WGET aufruft. Dort wird etwas in eine DB geschrieben...
Es kommt vor dass Ereignis X in 1 Sekunde 2 mal auftaucht. Also hab ich im Script überprüft ob der Eintrag von dem letzten Ereignis X bereits in der DB steht und nicht älter ist als 10 sekunden...

PHP:
//Hinweis: zs_max=strtotime(- 10 seconds);
SELECT ID FROM tabelle WHERE Zeitstempel>'$zs_max' LIMIT 1

Kommt Ereignis X1 z.B. um 22:00:05 vor wird es in DB eingetragen, kommt Ereignis X2 um 22:00:06 vor wird das 2. Ereignis unterdrückt und nicht eingetragen. Das funktioniert auch!

Kommt nun aber Ereignis X1 um 22:00:05 vor und Ereignis 2 auch um 22:00:05 vor werden beide in die DB geschrieben...

Erklären würde ich mir selbst das so:
WGET ruft durch die 2 - nur um Bruchteil von sek. - aufeinanderfolgenden Ereignisse die PHP Seite auf und der PHP-Interpreter arbeitet diese parallel ab und die o.g. Prüfung auf doppeleintrag greift nicht!

Das steht m.e. zum Widerspruch dazu, dass ich irgendwo mal gelesen habe, dass PHP auf dem Server alle Anfragen nacheinander abarbeitet...

Kann mir dass jemand mal kurz erklären? :confused:
Wie kann ich das Problem lösen? :confused:

Noch ein Hinweis falls wichtig: Die Seite liegt auf Shared Webspace (kein Freehoster)
 
Das steht m.e. zum Widerspruch dazu, dass ich irgendwo mal gelesen habe, dass PHP auf dem Server alle Anfragen nacheinander abarbeitet...

Du schreibst aber in SQL, da müsstest ansetzen. Deine Anweisung umschreiben und die Tabelle, in die du schreibst, während dem UPDATE / INSERT schützen per LOCK TABLES.
 
PHP:
(...)LOCK TABLES

Hab ich auch schon dran gedacht.

D.h. ich nutze lock table bei jedem aufruf und nach dem aufruf "unlock" ich nochmal...
Wird dann die Abfrage aus 2. Aufruf einfach "nachträglich" ausgeführt? Oder wie versteh ich das!?
 
Genau so ist es. Wenn du also verhindern willst, dass etwas zweimal eingetragen wird schreibst eine passende Kontrollstruktur um das ganze herum (IF oder INSERT ON DUPLICATE KEY UPDATE).
 
Also mach ich

PHP:
LOCK TABLES tabelle WRITE
SELECT ID FROM tabelle WHERE Zeitstempel>'$zs_max' LIMIT 1  
UNLOCK TABLES

Wenn Ereignis X1 kommt wird es in die DB geschrieben und wenn Ereignis X2 kommt wird es erst nach dem Ereignis X1 in die DB geschrieben...

Oder steh' ich noch auf dem Schlauch!? :(
 
Ich kenne dein Datenbankmodell nicht, von daher könnte ich nur raten.

Du solltest versuchen dein Problem im ganzen auf der Modell-/Datenschicht (SQL) zu lösen und deine bisherige Hybrid-Lösung (PHP + SQL) wegschmeißen, da mehrere PHP Threads gleichzeitig laufen und vieles komplizierter machen. Beispiel (verzahnt):

  • Thread 1 startet
  • Thread 2 startet
  • T1: Liest Daten
  • T2: Liest Daten
  • T1: Sieht nichts neues
  • T2: Sieht nichts neues
  • T1: schreibt
  • T2: schreibt

Daher lieber nur auf der Modell-/Datenschicht arbeiten:
  • T1 start
  • T2 start
  • T1: LOCK
  • T1: Liest Daten
  • T2: LOCK - wird verweigert und nach hinten geschoben (>>)
  • T1: Schreibt Daten
  • T1: UNLOCK
  • T2: (>>) Darf wieder
  • T2: LOCK
  • T2: Liest
  • ...

Wenn für sowas 1000 Anfragen pro Sekunde kommen geht dein Server aber in die Knie. Einfacher wäre das Modell deiner Datenbank ein wenig abzuändern, indem du z.B. aus der Zeit ein UNIQUE-Feld oder sogar ein Schlüssel machst. Diese können nicht doppelt vorkommen und die einzige Anweisung die du danach noch losschickst ist: "Schreiben!". Das Prüfen und verhindern von Redundanz macht die Datenbank dann von selbst.
 
Daher lieber nur auf der Modell-/Datenschicht arbeiten:

* T1 start
* T2 start
* T1: LOCK
* T1: Liest Daten
* T2: LOCK - wird verweigert und nach hinten geschoben (>>)
* T1: Schreibt Daten
* T1: UNLOCK
* T2: (>>) Darf wieder
* T2: LOCK
* T2: Liest
* ...

Sorry aber ich kann Dir nicht mehr folgen... :p

Es gibt max 2 Anfragen aber es kann sein dass diese zeitgleich kommen...

Hmmm!?

Deine 2. Lösung versteh ich in der Logik leider auch nicht!

Ich hab nach den 2 Threads 2 einträge die identisch bis auf einen unique-key sind... Das Problem ist nach dem schreiben in die DB geht das Script so weiter, dass es nur etwas macht wenn der Eintrag nicht schon vorhanden war...

Oder ich steh' schon wieder auf dem Schlauch...:confused:
 
Das Problem ist nach dem schreiben in die DB geht das Script so weiter, dass es nur etwas macht wenn der Eintrag nicht schon vorhanden war

Und hier gehen beide Skripte weiter wenn sie nahezu zeitgleich angestoßen werden, nicht wahr?
(Deine Problembeschreibung springt aber gut hin und her ;) )

Von daher mit dem LOCK arbeiten, damit eines der beiden Skripte merkt: "Ah, da trägt grad eine andere PHP-Instanz etwas ein."
Oder (einfacher) aus dem Datum / DATETIME / TIMESTAMP ein UNIQUE (aber kein Key) machen, damit das Skript merken kann: "Ah, ich versuche gerade etwas zu überschreiben, was eine andere Instanz zeitgleich macht."

In beiden Fällen arbeitet die eine Instanz so weiter wie du es möchtest und die andere kann abgebrochen werden.
SQL ist mächtig genug um dein Problem zu lösen. Also nicht mehr so sehr in PHP denken.
 
Zuletzt bearbeitet:
Zurück