Zur Navigation

Skript in Dauerschleife?

1 Ranma (Gast)

Der Versuch, Werte aus dem XML-Dump des deutschsprachigen Wiktionarys in eine MySQL-Datenbank zu laden, führt nach mehreren Stunden scheinbarer Untätigkeit zu folgender Fehlermeldung:


Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 7590 bytes) in /opt/lampp/htdocs/wiktionary.php on line 107


Zeile 107 lädt mögliche Übersetzungen in ein Array. Das passiert innerhalb einer weiteren Schleife. Der Code plus Zeilennummern:

105    while(substr_count($Daten3,'♚')>0 and substr_count($Daten3,'♙')>0):
106             $Zwischen=substr($Daten3,strpos($Daten3,'♚'),strpos($Daten3,'♙')-strpos($Daten3,'♚'));
107             $Daten2[]=$Zwischen;
108             str_replace($Zwischen,'',$Daten3);
109    endwhile;

Mit den Schachsymbolen wurden zuvor die Muster (Reguläre Ausdrücke) \{\{Ü\|(.*)\}\} und \{\{Üt\|(.*)\}\} und \{\{Ü\|(.*)\}\} \{\{(.*)\}\} und \{\{Üt\|(.*)\}\} \{\{(.*)\}\} ersetzt, weil die alle Übersetzungen enthalten (Ü ohne und Üt mit zusätzlicher Transkription; beim optionalen zweiten Doppelpaar geschweifter Klammern steht der Genus darin, das wird noch einen Schritt vorher vereinheitlicht, so daß das Leerzeichen auch nicht mehr vorhanden sein kann, sonst müßte da natürlich noch \s stehen).

Kann das eine Dauerschleife sein?

11.05.2016 02:02

2 Jörg

Kann es sein, dass $Daten2 zu groß wird für den Speicher?

Mit memory_get_usage() kann man messen, wieviel Speicher ein Script an welchen Stellen verbraucht (in diesem Fall die Ausgabe vor und nach der Schleife einfügen). Testen könntest du dabei z.B. mit einem Teil-Dump und dann hochrechnen

11.05.2016 13:26 | geändert: 11.05.2016 13:29

3 Ranma (Gast)

Zu viel Speicherverbrauch halte ich für unwahrscheinlich, weil ich den Dump eigentilch schon in Teilen von <page> bis </page> verarbeite.

Aber ich finde noch etwas am Verhalten des Skripts seltsam. Dafür mache ich ein neues Thema auf.
Ranma

12.05.2016 02:02

4 Jörg

Zu viel Speicherverbrauch halte ich für unwahrscheinlich

Darauf verweist aber die Fehlermeldung. Das Script möchte mehr als die erlaubten 134.217.728 Bytes allozieren.

12.05.2016 16:36

5 Ranma (Gast)

Das ist sicherlich ein Hinweis auf eine Dauerschleife?

Inzwischen habe ich bemerkt, daß es schon deswegen eine Dauerschleife sein müßte, weil meine Methode, den Substring zu gewinnen, den vorderen Delimiter einschließt und den hinteren Delimiter ausschließt. Das habe ich inzwischen korrigiert. Aber die Fehlermeldung bleibt.

Außerdem habe ich nun am Anfang set_time_limit(100); aber es dauert viel länger als hundert Sekunden bis die Fehlermeldung auftaucht. Das ist vielleicht ein Hinweis darauf, daß das Skript auf MySQL wartet. Aber die Query, die auch nichts weiter tut als die Stored Procedure aufzurufen, kommt erst nach der fraglichen WHILE-Schleife.

Läßt sich irgendwie feststellen, ob eine Query ausgeführt wurde? Mit einer SELECT-Query ginge das natürlich; wäre die umständliche Art, weil ich dafür auf eine andere Datenbank, die schon Werte enthält, zugreifen müßte. So ließe sich nicht gleich feststellen, ob vielleicht mit der Datenbank oder der Query etwas nicht stimmt.

Wahrscheinlich muß ich wieder einige Stunden in die Fehlersuche investieren, also werde ich auch mal memory_get_usage() einbauen.
Ranma

13.05.2016 01:16

6 Ranma (Gast)

Jetzt ist mir noch aufgefallen, daß die fragliche Zeile zwar eine Funktion enthält, die ein Ergebnis liefern dürfte, aber das noch keiner Variablen zugewiesen wird. Das habe ich jetzt auch noch korrigiert. Aber gebracht hat das auch nichts. Mit den Korrekturen und echo memory_get_usage(); ist die vorherige Zeile 107 nun Zeile 112 und Zeile 108 ist nun Zeile 113.

Die Ausgabe lautet nun:

586916
Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 7581 bytes) in /opt/lampp/htdocs/wiktionary.php on line 113

Die erste Zeile der Ausgabe ist das Resultat von memory_get_usage(); danach kommt die Fehlermeldung. Das zweite memory_get_usage(); also das nach der WHILE-Schleife, wird nicht erreicht. Damit kann ich das ganz sicher als Dauerschleife betrachten. Ich weiß nur nach wie vor nicht, warum das eine Dauerschleife ist.
Ranma

14.05.2016 01:33

7 Jörg

Du hast wie von mir empfohlen mit einem kleineren Dump getestet?

Ansonsten kannst du eine Schleife (zur Analyse) auch nach einer maximalen Anzahl von Durchläufen stoppen:

$max = 100;
$i = 0;
while (/* ... */ && $i <= $max) {
    /* ... */
    $i++;
}

17.05.2016 20:00 | geändert: 17.05.2016 20:00

8 Ranma (Gast)

Ich habe angefangen, das Skript neu zu schreiben. Aufgeteilt auf mehrere Skripte. Mit einigen davon bin ich fertig und die haben nur die Daten aus der einen Datei ausgelesen und relevante Daten in eine andere Datei geschrieben. Das erste Skript hing auch gleich nochmal in einer Dauerschleife. Auch da eine WHILE-Schleife innerhalb der WHILE-Schleife, die den Dateizeiger durch die gesamte Datei schickt. Gibt es eine Regel gegen das Verschachteln von WHILE-Schleifen?

Eigentlich habe ich nur deswegen mehrere Skripte zum entfernen irrelevanter Informationen verwendet, um das Verschachteln von WHILE-Schleifen zu vermeiden. So lief es zwar nicht ganz problemlos, aber ohne Dauerschleifen. Statt einer über 800 MB großen Ausgangsdatei muß ich nun nur noch ungefähr 16 MB verarbeiten.

PHP ist übrigens recht schnell, wenn man eine Datei, auch wenn sie groß ist, verarbeitet und das Ergebnis in eine andere Datei schreibt. Das dauert nur Sekunden, während eintragen in eine Datenbank Stunden bis Tage gedauert hätte.
Ranma

18.05.2016 01:39

Beitrag schreiben (als Gast)





[BBCode-Hilfe]