Rechenintensives Script verhindert weitere Requests
Baba
- webserver
Liebe Gemeinde,
ich habe ein php-Script, welches mittels exec ein Programm aufruft (process.exe), welches sehr rechenintensiv ist. Auf meinem Laptop läuft es ca 4 Minuten. Auf dem PC ca 2.
Damit die Seite nicht minutenlang weiß zeigt, habe ich das ganze in ein php-Script ausgelagert, das ich mittels AJAX aufrufe. Klappt soweit super.
Nur kann ich jetzt zum Beispiel nicht:
a) einen neuen Tab öffnen und weiterbrowser
b) einen weiteren AJAX Request zum Script alle 2 Sekunden starten
Das Problem wurde mir klar, als ich versuchte, sowas wie 2) zu realisieren, um den Fortschritt zu erfassen. process.exe schreibt einen Index von 1-600 in eine Textdatei und mit diesem wollte ich eine Fortschrittsanzeige realisieren. Nur kommt dieses zweite Script gar nicht zu dem Server durch, solange nicht das erste Script gelaufen ist. Dies habe ich mit Firebug rausgekriegt.
Die Frage nun:
Ich benutze WAMP als Server.
Cheers,
Baba
Hallo,
Das Problem wurde mir klar, als ich versuchte, sowas wie 2) zu realisieren, um den Fortschritt zu erfassen. process.exe schreibt einen Index von 1-600 in eine Textdatei und mit diesem wollte ich eine Fortschrittsanzeige realisieren. Nur kommt dieses zweite Script gar nicht zu dem Server durch, solange nicht das erste Script gelaufen ist. Dies habe ich mit Firebug rausgekriegt.
Bist du dir da sicher? Ich würde vermuten das das zweite script nicht auf die Datei zugreifen kann, solange das erste Script darin rumschreibt und deshalb wartet, bist das erste script fertig ist. Vielleicht kommt der Request ja beim Server an. Nun sendet der halt nichts zurück.
Viele Grüße Novi
Bist du dir da sicher? Ich würde vermuten das das zweite script nicht auf die Datei zugreifen kann, solange das erste Script darin rumschreibt
Vielen Dank für Deine Antwort.
Was Du schreibst macht Sinn für diesen Fall. Und ich kann derzeit nicht rausfinden, ob der externe Prozess den Handler auf die Indexdatei nie schliesst. Aaaaaaaber: müsste dann nicht 1) ohne Probleme gehen? (Einen neuen Tab der Website öffnen.)
Habe gerade noch etwas bemerkt. Der Server generell ist wohl nicht zu busy. Vielleicht kann mir nochmal einer helfen.
Wenn ich während des langen Prozesses die index.php öffnen will (Startseite) geht das nicht, bis der lange Prozess fertig ist. Wenn ich allerdings zB. playground.php öffenen will, geht das sofort.
Die Seite, die den Ajax beinhaltet ist index.php/matlab2. Es ist eine völlig andere Seite, die aber über die index.php geht. Alle Seiten gehen bei mir über die index.php
Das Ziel des Ajax Requests ist route.php
Kann es sein, dass während des langen Prozesses die index.php geblockt ist?
Moin!
Das Problem wurde mir klar, als ich versuchte, sowas wie 2) zu realisieren, um den Fortschritt zu erfassen. process.exe schreibt einen Index von 1-600 in eine Textdatei und mit diesem wollte ich eine Fortschrittsanzeige realisieren. Nur kommt dieses zweite Script gar nicht zu dem Server durch, solange nicht das erste Script gelaufen ist. Dies habe ich mit Firebug rausgekriegt.
Ist eine Session aktiv? Dann setzt jedes Skript ein Lock auf die Session, damit sich zwei gleichzeitige Skripte nicht unsachgemäß die Daten zerstören - als Effekt werden alle Skripte auf dieselbe Session seriell abgearbeitet.
session_write_close() wäre eine Alternative. Damit schreibst du die Session weg und schließt die Session-Datei. Danach kannst ein anderes Skript die Session weiterführen. Allerdings hat das erste Skript danach keine Möglichkeit mehr, noch was in die Session zu speichern.
- Sven Rautenberg
Ist eine Session aktiv? Dann setzt jedes Skript ein Lock auf die Session, damit sich zwei gleichzeitige Skripte nicht unsachgemäß die Daten zerstören - als Effekt werden alle Skripte auf dieselbe Session seriell abgearbeitet.
Wow, ich liebe dieses Forum einmal mehr. Ich hatte keine Idee mehr.
Also, das erklärt einiges. Ja, es ist eine Session aktiv. Und bei jenem playground-script, was sich laden lässt, wird eben keine gestartet. Das erklärt auch, warum ich mit einem anderen Browser parallel zugreifen kann.
Ich werde das morgen, ausgeschlafen sofort probieren.
Vielen lieben Dank.
Grüße,
Baba
Hello,
Ist eine Session aktiv? Dann setzt jedes Skript ein Lock auf die Session, damit sich zwei gleichzeitige Skripte nicht unsachgemäß die Daten zerstören - als Effekt werden alle Skripte auf dieselbe Session seriell abgearbeitet.
Wow, ich liebe dieses Forum einmal mehr. Ich hatte keine Idee mehr.
Also, das erklärt einiges. Ja, es ist eine Session aktiv. Und bei jenem playground-script, was sich laden lässt, wird eben keine gestartet. Das erklärt auch, warum ich mit einem anderen Browser parallel zugreifen kann.
Zwei Browser -> i.d.R. zwei unterschiedliche Sessions. Die beißen sich also nicht.
Selber Browser -> i.d.R. begrenzt auf z.B. 2 (oder auch 8, je nach Browser) offene Requests pro Domain. Das kann man am Browser zwar meistens konfigurieren, aber das Konfigurieren kann man schlecht von jedem User verlangen...
Alternative:
Das rechenintensive Script per ecec() in den Hintergrund stellen. Dort läuft das dann auch weiter, ohne dass die Browserseite noch offen ist. Da kannst Du dann gelegentlich nachfragen (per Ajax), wie weit es schon gediehen ist.
Im Archiv findest Du eine Reihe von Beiträgen zum Thema
z.B.:
http://forum.de.selfhtml.org/archiv/2007/1/t145034/#m941113
http://forum.de.selfhtml.org/archiv/2007/3/t149507/#m971082
usw.
Liebe Grüße aus dem schönen Oberharz
Tom vom Berg
Moin!
Hello,
Ist eine Session aktiv? Dann setzt jedes Skript ein Lock auf die Session, damit sich zwei gleichzeitige Skripte nicht unsachgemäß die Daten zerstören - als Effekt werden alle Skripte auf dieselbe Session seriell abgearbeitet.
Wow, ich liebe dieses Forum einmal mehr. Ich hatte keine Idee mehr.
Also, das erklärt einiges. Ja, es ist eine Session aktiv. Und bei jenem playground-script, was sich laden lässt, wird eben keine gestartet. Das erklärt auch, warum ich mit einem anderen Browser parallel zugreifen kann.
Zwei Browser -> i.d.R. zwei unterschiedliche Sessions. Die beißen sich also nicht.
"In der Regel"!?!
Selber Browser -> i.d.R. begrenzt auf z.B. 2 (oder auch 8, je nach Browser) offene Requests pro Domain. Das kann man am Browser zwar meistens konfigurieren, aber das Konfigurieren kann man schlecht von jedem User verlangen...
Wieviele Connections der Browser zum Server öffnet, ist egal. Die Grenze liegt bei einem Wert größer als 1. Also sind parallele Requests möglich und technisch auch erwünscht.
Aber wenn der Server die Abarbeitung eines Requests solange pausiert, bis das Session-File entsperrt ist, bringt das nichts.
Alternative:
Das rechenintensive Script per ecec() in den Hintergrund stellen. Dort läuft das dann auch weiter, ohne dass die Browserseite noch offen ist. Da kannst Du dann gelegentlich nachfragen (per Ajax), wie weit es schon gediehen ist.
Das Verlagern eines zeitaufwendigen Tasks in den Hintergrund hat denselben Effekt, wie das vorzeitige Wegschreiben und Freigeben des Session-Files.
Mit dem Vorteil, dass der Browser weiterhin mit Infos über den Fortgang versorgt werden könnte, aber am Ende eben kein Update der Session mehr stattfinden kann.
Im Archiv findest Du eine Reihe von Beiträgen zum Thema
z.B.:
http://forum.de.selfhtml.org/archiv/2007/1/t145034/#m941113
http://forum.de.selfhtml.org/archiv/2007/3/t149507/#m971082usw.
Das Problem hier ist Session-Locking. Davon schon mal gehört? Locking ist doch sonst dein Lieblingsthema, Nebenläufigkeit etc.
Locking wird übrigens gern vergessen, wenn man die Session-Daten lieber in einer Datenbank ablegen will.
- Sven Rautenberg
Hello,
Das Problem hier ist Session-Locking. Davon schon mal gehört?
warum so giftig?
Das Problem liegt ganz woanders, nämlich im Fehlen einer vernünftigen Planung für die Lösung der Aufgabe.
Liebe Grüße aus dem schönen Oberharz
Tom vom Berg
Das Problem liegt ganz woanders, nämlich im Fehlen einer vernünftigen Planung für die Lösung der Aufgabe.
Bitte kläre mich auf.
Cheers,
Baba
Moin!
Das Problem liegt ganz woanders, nämlich im Fehlen einer vernünftigen Planung für die Lösung der Aufgabe.
Bitte kläre mich auf.
Offensichtlich hat Tom daran kein Interesse mehr.
- Sven Rautenberg
Hello Baba & Sven,
Das Problem liegt ganz woanders, nämlich im Fehlen einer vernünftigen Planung für die Lösung der Aufgabe.
Bitte kläre mich auf.
Offensichtlich hat Tom daran kein Interesse mehr.
Das ist nicht "offensichtlich", sondern "vermutlich". Für ein "offensichtlich" sind die Indizien keinesfalls hinreichend. Oder kurz: ich ahbe es einfach nicht gesehen, dass hier noch eine reaktion kam.
Zum Thema:
Ich hatte in https://forum.selfhtml.org/?t=208288&m=1416282 schon erwähnt, dass es sinnvoller sein kann, das rechnenintensive Script auf dem Server in den Hintergrund zu stellen und es dann ggf. von Zeit zu Zeit dessen Zustand durch einen _kurzen_ Kontrollrequest abzufragen.
Dazu muss das Script selbstverständlich geeignet geschrieben sein. Die notwendigen Sessiondaten werden beim Start als Parameter oder in einer separaten Datei übergeben. In dieser separaten Datei kann das Script dann auch den Zustand melden.
Die Verbindung zur Standardausgabe zu halten kostet nach meinen Erfahrungen viel mehr Kraft bzw. Zeit, als eine Ausgabe in eine Datei zu lenken. Woran das liegt, habe ich nicht untersucht, vermute aber, dass es nicht anders ist, als beim guten alten DOS. Viele Umlenkungen kosten eben.
Warum soll ich also den Client blockieren und - viel wichtiger - einen Kanal vom Client zum Server dauerhaft blockieren, wenn es mit kurzen Kontrollrequests auch geht?
Baba sollte sich für derartige Vorgänge ein ausführliches Zeit-Aufgaben-Diagramm erstellen und erst dann "AJAX" oder andere Wunderwaffen einsetzen, wenn diese aufgrund guter Planung so kurz wie möglich eingesetzt werden können - dafür lieber öfter.
Es ist nicht sinnvoll, Verbindungsorientierung bei HTTP durch Gewalt herzustellen. Es ist besser, diese durch Logik nachzubilden.
Liebe Grüße aus dem schönen Oberharz
Tom vom Berg
Hello,
Es ist nicht sinnvoll, Verbindungsorientierung bei HTTP durch Gewalt herzustellen. Es ist besser, diese durch Logik nachzubilden.
Sollte eigentlich besser heißen:
... Zustandsorientierung durch erzwungene Verbindungsorientierung herzustellen. Es ist besser, die Zustandsorientierung durch Logik nachzubilden.
Liebe Grüße aus dem schönen Oberharz
Tom vom Berg
Alternative:
Das rechenintensive Script per ecec() in den Hintergrund stellen.
exec() wartet aber auf den Prozess standardmäßig. Die Foren sind voll davon, dass es nicht gelingt "die Ausgabe umzulenken". Da das ganze auf jedem OS auch noch anders ist, habe ich es gleich verworfen. Auch weil einige Stimmen sagen, das php dafür nicht das richtige Werkzeug ist, und es besser ist, das nicht zu erzwingen.
Dann setzt jedes Skript ein Lock auf die Session, damit sich zwei gleichzeitige Skripte nicht unsachgemäß die Daten zerstören - als Effekt werden alle Skripte auf dieselbe Session seriell abgearbeitet.
session_write_close() wäre eine Alternative. Damit schreibst du die Session weg und schließt die Session-Datei. Danach kannst ein anderes Skript die Session weiterführen. Allerdings hat das erste Skript danach keine Möglichkeit mehr, noch was in die Session zu speichern.
Juhu. Das war das Problem. Ich kriege jetzt eine schöne Anzeige (x von 600 Läufen), wie ich das wollte. Das Problem war wirklich das Session locking.
VIELEN DANK für diesen super Tipp. Habe es mit
@session_write_close();
geschafft. Das @ war nötig, weil ich eine Fehlermeldung mit folgendem Wortlaut bekam, die ich nicht verstehe (da ich keinen Falls register_globals on setzen möchte):
<fehler>
Warning: Unknown(): Your script possibly relies on a session side-effect which existed until PHP 4.2.3. Please be advised that the session extension does not consider global variables as a source of data, unless register_globals is enabled. You can disable this functionality and this warning by setting session.bug_compat_42 or session.bug_compat_warn to off
</fehler>
Auch wollte ich nicht unbedingt irgendwelche Error reporting levels runtersetzen, wie
session.bug_compat_42 = 0
session.bug_compat_warn = 0
in der .htaccess
Wenn noch jemand eine Idee zu der Fehlermeldung (oder eigentlich nur dem Hinweis) hat...
Cheers,
Baba
[...] Idee zu der Fehlermeldung (oder eigentlich nur dem Hinweis) hat...
Du versuchst offenbar eine Variable, die mit register_globals global Gültigkeit wäre in die Session zu schreiben:
z.B.
$_SESSION['var'] = $var;
oder
$_SESSION['var'] = $_POST['var'];
oder
$_SESSION['var'] = 'foo';
$var = 'bar';
Moin!
Das @ war nötig, weil ich eine Fehlermeldung mit folgendem Wortlaut bekam, die ich nicht verstehe (da ich keinen Falls register_globals on setzen möchte):
<fehler>
Warning: Unknown(): Your script possibly relies on a session side-effect which existed until PHP 4.2.3. Please be advised that the session extension does not consider global variables as a source of data, unless register_globals is enabled. You can disable this functionality and this warning by setting session.bug_compat_42 or session.bug_compat_warn to off
</fehler>
Die Fehlermeldung sagt dir, was zu tun ist, damit diese Meldung nicht kommt. :)
Auch wollte ich nicht unbedingt irgendwelche Error reporting levels runtersetzen, wie
session.bug_compat_42 = 0
session.bug_compat_warn = 0in der .htaccess
Googlen nach der Meldung bringt diverse Ansätze.
1. Benutzt du session_register()?
2. Oder weist du undefinierte Variablen an $_SESSION zu?
Das @ ist jedenfalls keine so gute Idee, finde ich.
- Sven Rautenberg