LochNess: PHP - Skript - Threads

Guten Abend,

ich habe ein Problem :

Ich habe eine PHP-Internetpage entwickelt. Nach einem Klick läuft dort eine Simulation. Alles natürlich erst mal auf einem Localhost.
Nun durch diese Simulation (Sleep wird verwendet) ist nicht der ganze
CPU ausgelastet, aber es scheint auf jeden Fall so, das der Zugriff auf den Apache-Server ausgelastet ist.

Ich will nähmlich während der Simulation im Firefox einen neuen Tab aufmachen. In diesem neuen Tab die URL auf dem Localhost zu dieser
PHP-Internetpage nochmal aufmachen. Jeder Klick auf ein Button oder sonstiges funktioniert nicht, da die Simulation im anderen Tab gestartet worden ist (While-Schleife).

Gibt es eine Lösung ? Bestimmt, z.B. mit PHP als CGI, aber ich steh auf dem Schlauch wie ich das mache.

Versteht jemand das Problem ?

Grüsse aus LochNess :-)

  1. Hallo LochNess,

    Ich will nähmlich während der Simulation im Firefox einen neuen Tab aufmachen. In diesem neuen Tab die URL auf dem Localhost zu dieser
    PHP-Internetpage nochmal aufmachen. Jeder Klick auf ein Button oder sonstiges funktioniert nicht, da die Simulation im anderen Tab gestartet worden ist (While-Schleife).

    Gibt es eine Lösung ? Bestimmt, z.B. mit PHP als CGI, aber ich steh auf dem Schlauch wie ich das mache.

    Versteht jemand das Problem ?

    Nein, das verstehe ich nicht - normalerweise sollte ein laufendes PHP-Skript andere PHP-Skripte nicht auf diese Art und Weise beeinflussen.

    Aber du verschweigst einige Informationen:

    • Was verstehst du unter 'Simulation'? Ist das nur PHP-Code, oder eher ein externes Programm, das von PHP aus gestartet wird? Beeinflussen sich Instanzen dieses Programmes?
    • Alle Browser haben üblicherweise eine Begrenzung eingebaut, wie viele Elemente gleichzeitig von einem Server geladen werden können. Wenn du den Tab im Firefox offen hast und die Simulation läuft, was passiert, wenn du die Seite nochmal in einem anderen Browser aufrufst? Und was passiert, wenn du die Seite noch mal von einem völlig anderen Rechner aufrufst?

    Grüße

    Marc Reichelt || http://www.marcreichelt.de/

    --
    Linux is like a wigwam - no windows, no gates and an Apache inside!
    Selfcode: ie:{ fl:| br:> va:} ls:< fo:} rl:( n4:( ss:) de:> js:| ch:? sh:| mo:) zu:)
    1. Hallo Marc,

      Nein, das verstehe ich nicht - normalerweise sollte ein laufendes PHP-Skript andere PHP-Skripte nicht auf diese Art und Weise beeinflussen.

      Anscheinend tut das es aber.

      Aber du verschweigst einige Informationen:

      • Was verstehst du unter 'Simulation'? Ist das nur PHP-Code, oder eher ein externes Programm, das von PHP aus gestartet wird? Beeinflussen sich Instanzen dieses Programmes?

      Nur PHP-Code. Kein Externes Programm. Es ist ein PHP-Code, angenommen
      test.php. In test.php wird etwas berechnet bzw. simuliert. Das kann von ca. 1 Minute bis 5 Stunden laufen. 5 Stunden würden aber runter skaliert werden. Die Berechnung ist eine While-Schleife innendrinne mit einer Sleep-Funktion. Die Sleep-Funktion löst dann halt die Gesamtzeit aus, wie z.B. simulierte 5 Stunden = 30 Minuten.

      So wenn ich jetzt einen neuen Tab aufmache mit dieser URL (z.B. http://localhost/Simulation/index.php) öffnet sich nicht einmal die Page. Der localhost scheint ziemlich ausgelastet zu sein.

      Verstehst du jetzt besser das Problem ?

      1. Hallo LochNess,

        So wenn ich jetzt einen neuen Tab aufmache mit dieser URL (z.B. http://localhost/Simulation/index.php) öffnet sich nicht einmal die Page. Der localhost scheint ziemlich ausgelastet zu sein.

        Nö, ist er nicht.
        Ich habe mir ein einfaches Skript gebastelt, das einfach eine Stunde dauert:

        <?php  
          
        error_reporting(E_ALL);  
        ini_set('max_execution_time', 30);  
          
        for ($i = 1; $i <= 3600; $i++) {  
                echo $i.' ';  
                flush();  
                sleep(1);  
        }  
          
        ?>
        

        Ich kann dein Problem nachvollziehen - im Firefox wird der zweite Tab nicht geladen, bevor der zweite nicht fertig ist. Im Opera geschieht auch etwas witziges: Der zweite und der erste Tab laden beide das Gleiche.

        Am Server liegt es jedenfalls nicht - mehrere wget-Instanzen können unabhängig voneinander unterschiedliche Resultate speichern.

        Das Problem liegt also auf der Client-Seite. Nach ein paar Sekunden kam ich jetzt drauf, was der Browser wohl so denkt, wenn du ihm aufgibst, das Gleiche nochmals zu laden:
        1. Öffne http://localhost/test.php im 1. Tab.
        2. Ladevorgang beginnt.
        3. Öffne http://localhost/test.php im 2. Tab.
        4. http://localhost/test.php muss nicht erneut geladen werden - Tab 1 bearbeitet ihn ja bereits.

        Eine einfache Lösung ist ein Aufruf mit einem entsprechendem Dummy-Parameter:
        http://localhost/test.php?dummy=1
        http://localhost/test.php?dummy=2
        http://localhost/test.php?dummy=xyz

        Grüße

        Marc Reichelt || http://www.marcreichelt.de/

        --
        Linux is like a wigwam - no windows, no gates and an Apache inside!
        Selfcode: ie:{ fl:| br:> va:} ls:< fo:} rl:( n4:( ss:) de:> js:| ch:? sh:| mo:) zu:)
        1. Hi,

          danke für deine Hilfe. Ich probiers mal. Dummys :-), wie bist du darauf gekommen ? Da wäre ich nicht darauf gekommen. Man lernt nie aus...

          Sag mal was sind wget-Instanzen. Habe noch nie damit gearbeitet?

          Gruss aus LochNess

          1. Hallo LochNess,

            danke für deine Hilfe. Ich probiers mal. Dummys :-), wie bist du darauf gekommen ? Da wäre ich nicht darauf gekommen. Man lernt nie aus...

            Sag mal was sind wget-Instanzen. Habe noch nie damit gearbeitet?

            Ach, ich fachkauderwelsche[0] mal wieder. wget ist ein Konsolenprogramm für Linux, mit dem man einfach Dateien herunterladen kann (hat sehr viele Funktionen, sogar Rekursion).
            Gibt's auch für Windows.

            Ich habe einfach in einer Konsole "wget http://localhost/test.php" ausgeführt, und in einer zweiten (in einem anderen Ordner) ebenfalls "wget http://localhost/test.php". Da die beiden Instanzen getrennt voneinander arbeiten bekommen sie voneinander nicht mit, dass der jeweils andere gerade die gleiche Adresse lädt - und starten so eben auch die Requests unabhängig voneinander.

            Grüße

            Marc Reichelt || http://www.marcreichelt.de/

            [0] Hui, was eine schöne Wortneuschöpfung.

            --
            Linux is like a wigwam - no windows, no gates and an Apache inside!
            Selfcode: ie:{ fl:| br:> va:} ls:< fo:} rl:( n4:( ss:) de:> js:| ch:? sh:| mo:) zu:)
            1. Sag mal was sind wget-Instanzen. Habe noch nie damit gearbeitet?

              Ach, ich fachkauderwelsche[0] mal wieder. wget ist ein Konsolenprogramm für Linux, mit dem man einfach Dateien herunterladen kann (hat sehr viele Funktionen, sogar Rekursion).
              Gibt's auch für Windows.

              Achso... Man und irgendwas ist mit meinem Gedächtnis. Klar kenne ich wget. Ich glaube es gibt auch ein wput oder ? Naja, hab das mal benutzt.Muss mal wieder Linux installieren :-)

              Gute Nacht aus LochNess...

              P.S. Man ist es hier kalt

            2. Hi nochmal,

              das Problem liegt wo anders :-). Deine Lösung ist schon richtig.
              Aber ich habe dir noch etwas verschwiegen. In der Simulation greife ich auf die Datenbank zu. So in einem anderen Tab wird dasselbe nochmal probiert. Das geht aber nicht, da ein handle auf die Datenbank schon offen ist.

              Normalerweise kann man doch mehrere Datebankhandles aufmachen oder ?
              Aber wahrscheinlich nicht vom selben localhost oder ?

              Gruss

              1. Hallo

                In der Simulation greife ich auf die Datenbank zu. So in einem anderen Tab wird dasselbe nochmal probiert. Das geht aber nicht, da ein handle auf die Datenbank schon offen ist.

                Normalerweise sollte jede Instanz des PHP-Skriptes bei der Verbindungsaufnahme mit dem DB-Server eine eigene Verbindungskennung bekommen. Alles andere wäre Quatsch, da einunddasselbe Skript z.B. auf einer stark frequentierten Website ebenfalls mehrfach am Laufen ist.

                Tschö, Auge

                --
                Die Musik drückt aus, was nicht gesagt werden kann und worüber es unmöglich ist zu schweigen.
                (Victor Hugo)
                <dingdong /><dingdong /><toc /><toc /><toc /><shout>Florence!</shout>
                Veranstaltungsdatenbank Vdb 0.1
            3. Hi,

              ich habe den Fehler gefunden. In diesen PHP-Dateien gab
              es ein "session_start()"...

              Aus irgendeinem Grund musste ich die auskommentieren, da sonst
              dieser komische Effekt aufgetaucht war.

              Verstehst du das?

              1. Hallo LochNess,

                Verstehst du das?

                Momentan nicht, morgen nicht und auch im Traum nicht.
                Das sind Probleme die nur du alleine lösen kannst, da du nicht mit den Informationen rausrückst.

                Grüße

                Marc Reichelt || http://www.marcreichelt.de/

                --
                Linux is like a wigwam - no windows, no gates and an Apache inside!
                Selfcode: ie:{ fl:| br:> va:} ls:< fo:} rl:( n4:( ss:) de:> js:| ch:? sh:| mo:) zu:)
              2. Moin!

                ich habe den Fehler gefunden. In diesen PHP-Dateien gab
                es ein "session_start()"...

                Aus irgendeinem Grund musste ich die auskommentieren, da sonst
                dieser komische Effekt aufgetaucht war.

                Verstehst du das?

                Das ist korrekt. Aufrufe derselben Session müssen sich gegenseitig blockieren, weil ansonsten die Session-Daten durcheinandergeraten.

                Angenommen, du hast zwei Skripte. Das erste setzt den Session-Wert "A", das zweite den für "B". Beide werden "gleichzeitig" in zwei Fenstern des Browsers aufgerufen.

                Erwartungshaltung: Am Ende der beiden Skripte stehen in der Session die Werte von "A" und "B".

                Ablauf: Skript "B" wird einen Tick früher gestartet. Es sperrt die Session-Datei, in der noch absolut "nichts" steht, das Skript läuft durch, der Wert "B" wird in der Session gespeichert, die Sessiondaten werden in die Datei gespeichert, die Datei wird wieder freigegeben. Skript "A" hat solange warten müssen, es liest die Sessiondatei mit "B" ein, fügt "A" hinzu, speichert wieder und gibt die Sessiondatei frei. Jetzt kann Skript "C" die beiden Werte "A" und "B" lesen, wie erwartet.

                Wenn Skript A und B tatsächlich gleichzeitig laufen würden, würden beide eine leere Sessiondatei vorfinden, jeweils nur separat "A" oder "B" anlegen und speichern. Das Skript, welches zuletzt speichert, überschreibt das Ergebnis des vorherigen Skriptes, und man kann am Ende nicht "A" UND "B" auslesen, sondern nur eines von beidem. Deshalb sind die Sessiondaten für die Laufzeit des Skriptes gesperrt. Wenn du diese Laufzeit durch sleep() künstlich verlängerst, sperrst du die gesamte Session, die damit zusammenhängt. Mit anderen Worten: Sessions sind bei deiner "Simulation" nicht nutzbar, solange du auf sleep() bestehst.

                - Sven Rautenberg

                --
                "Love your nation - respect the others."
                1. hi,

                  Mit anderen Worten: Sessions sind bei deiner "Simulation" nicht nutzbar, solange du auf sleep() bestehst.

                  Wenn man vor dem Schlafengehen session_write_close() benutzt, sollte man damit nicht "hängen bleiben".
                  Setzt aber natürlich voraus, dass man alles, was man mit den Sessiondaten im Script anstellen will, vorher "fertig" hat.

                  gruß,
                  wahsaga

                  --
                  /voodoo.css:
                  #GeorgeWBush { position:absolute; bottom:-6ft; }
                  • Sven Rautenberg

                  Hallo,

                  klingt sehr logisch, was du da geschrieben hast. Ist das selbe
                  wie mit Pipes, Semaphoren etc. Da wird auch blockiert bis eine Semaphore
                  für eine Resource wieder freigegeben wird. (Philosophen-Problem).

                  Mit anderen Worten: Sessions sind bei deiner "Simulation" nicht
                  nutzbar, solange du auf sleep() bestehst.

                  Was kann man den anstatt sleep() benutzen ?

                  Vielen dank für all die Hilfe. Es geht auch ohne Zankerei, Wahsaga etc. :-)

                  Gruss
                  SmartyShark

                  1. echo $begrüßung;

                    Was kann man den anstatt sleep() benutzen ?

                    Das kommt darauf an, was du eigentlich vorhast.

                    sleep() ist dafür gedacht, dass ein Script für kurze Wartezeiten keine Ressourcen benötigt. Statt immer wieder abzufragen, ob eine Ressource zur Verfügung steht, und damit die CPU zu beschäftigen, wartet man halt zwischen zwei Anfragen eine bestimmte Zeit.

                    Möchte man anderen eine Wartezeit aufdrängeln, während der sie nichts machen dürfen, so antwortet man auf deren Requests, die etwas machen wollen, mit "jetzt nicht" oder auch mit "erst um x:xx Uhr wieder". Wenn man die verbleibende Wartezeit oder den Wartezustand am Client anzeigen möchte, so kann man das mittels clientseitigem Scripting besser lösen. Das belastet den Server nicht mit offenen aber ungenutzten Verbindungen und anderem Ressourcenverbrauch.

                    echo "$verabschiedung $name";

        2. echo $begrüßung;

          Eine einfache Lösung ist ein Aufruf mit einem entsprechendem Dummy-Parameter:
          http://localhost/test.php?dummy=1
          http://localhost/test.php?dummy=2
          http://localhost/test.php?dummy=xyz

          Ich denke eher, dass das Problem durch Ändern der Programmlogik zu lösen ist. Wenn man Wartezeiten braucht, z.b. bis ein virtuelles Gebilde fertiggebaut ist, so sollte man diese Zeitinformationen (Startzeit und Baudauer) in den Daten des Gebildes speichern und bei Anforderungen berechnen, ob das Gebilde noch im Bau ist oder schon fertig.

          echo "$verabschiedung $name";

  2. hi,

    Ich habe eine PHP-Internetpage entwickelt. Nach einem Klick läuft dort eine Simulation. Alles natürlich erst mal auf einem Localhost.
    Nun durch diese Simulation (Sleep wird verwendet) ist nicht der ganze
    CPU ausgelastet, aber es scheint auf jeden Fall so, das der Zugriff auf den Apache-Server ausgelastet ist.

    Wenn irgendwo sleep verwendet wird, kann man in > 99% der Fälle davon ausgehen, dass es alles andere als das "Gelbe vom Ei" ist.

    Was simulierst du denn da, was ein "Schlafen" nötig machen würde?

    Ich will nähmlich während der Simulation im Firefox einen neuen Tab aufmachen. In diesem neuen Tab die URL auf dem Localhost zu dieser
    PHP-Internetpage nochmal aufmachen. Jeder Klick auf ein Button oder sonstiges funktioniert nicht, da die Simulation im anderen Tab gestartet worden ist (While-Schleife).

    Browser bauen nur eine sehr limitierte Anzahl von Verbindungen zu einem Server auf - lange Zeit war der Defaultwert glaube ich 2 Stück, ob das heute noch so ist, kann ich nicht sagen.

    Fakt dürfte aber auf jeden Fall sein, dass du mit so einer Schlaf-Simulation zumindest schon mal eine dieser möglichen Verbindungen auf längere Dauer "blockiert" hältst.

    gruß,
    wahsaga

    --
    /voodoo.css:
    #GeorgeWBush { position:absolute; bottom:-6ft; }
    1. Hallo wahsaga,

      Browser bauen nur eine sehr limitierte Anzahl von Verbindungen zu einem Server auf - lange Zeit war der Defaultwert glaube ich 2 Stück, ob das heute noch so ist, kann ich nicht sagen.

      Beim Firefox 2 sind es aktuell 8 ("network.http.max-connections-per-server").

      Grüße

      Marc Reichelt || http://www.marcreichelt.de/

      --
      Linux is like a wigwam - no windows, no gates and an Apache inside!
      Selfcode: ie:{ fl:| br:> va:} ls:< fo:} rl:( n4:( ss:) de:> js:| ch:? sh:| mo:) zu:)
  3. Hello,

    wenn Du nicht nur den Client am Weitermachen hindern willst, dann wäre vielleicht auch ein abgespaltener Prozess Dein Freund?

    Angenommen, Du willst am Server einen Vorgang starten, der länger dauert, und bei dem Du am Client nicht ununterbrochen zuschauen musst (z.B. Mailingliste abarbeiten), dann kannst Du den Vorgang auch mittels exec und PHP als CGI in den Hintergrund stellen. Der Vorgang hinterlässt dann an einer definierten Stelle Statusmeldungen und lässt sich so über ein weiteres Script gelegentlich beobachten. Auch zum Stoppen des Hintergrundprozesses sollte man wissen, wie die PID lautet.

    Harzliche Grüße vom Berg
    http://www.annerschbarrich.de

    Tom

    --
    Fortschritt entsteht nur durch die Auseinandersetzung der Kreativen
    Nur selber lernen macht schlau