hilfe! php wird immer langsamer
steffi
- php
hi.
hab nun lange versucht, herauszufinden, warum eines meiner import-scripte immer langsamer wird. nun scheine ich das time lag gefunden zu haben. es heißt str_replace(array())!
der erste durchgang geht schnell von statten. aber dann dauert es manchmal sogar 10x länger!
hierzu das schlampig geschriebene demonstrationsbeispiel:
<?
set_time_limit(0);
$ts_=0;
$testa[]='aaaaaaaaaaaaaaaaaaaaaaaaa';
$testa[]='bbbbbbbbbbbbbbbbbbbbbbbbb';
$testa[]='ccccccccccccccccccccccccc';
$testa[]='aaaaaaaaaaaaaaaaaaaaaaaaa';
$testa[]='bbbbbbbbbbbbbbbbbbbbbbbbb';
$testa[]='ccccccccccccccccccccccccc';
$testa[]='aaaaaaaaaaaaaaaaaaaaaaaaa';
$testa[]='bbbbbbbbbbbbbbbbbbbbbbbbb';
$testa[]='ccccccccccccccccccccccccc';
$testa[]='aaaaaaaaaaaaaaaaaaaaaaaaa';
$testa[]='bbbbbbbbbbbbbbbbbbbbbbbbb';
$testa[]='ccccccccccccccccccccccccc';
for($i=0;$i<10000;$i++)
{
$ts=time();echo ".";flush();
for($j=0;$j<1000;$j++)
$test=str_replace('aaa','bbb',$testa);
$ts_=$ts_+(time()-$ts);
$ts=time();
if(bcmod($i,100)==0)
{
echo '<br>'.$ts_.'<br>';
$ts_=0;
}
}
?>
was kann ich tun, damit jeder durchgang so schnell geht wie der erste?
danke
Hallo
str_replace(array())
str_replace ist eine _Stringfunktion_.
der erste durchgang geht schnell von statten. aber dann dauert es manchmal sogar 10x länger!
$testa[]='aaaaaaaaaaaaaaaaaaaaaaaaa';
$testa[]='bbbbbbbbbbbbbbbbbbbbbbbbb';
$testa[]='ccccccccccccccccccccccccc';
for($i=0;$i<10000;$i++)
{
$ts=time();echo ".";flush();
for($j=0;$j<1000;$j++)
$test=str_replace('aaa','bbb',$testa);
was kann ich tun, damit jeder durchgang so schnell geht wie der erste?
Die Funktion str_replace auf einen String und nicht auf das _ganze_ Array ($testa) anwenden.
Tschö, Auge
Hallo Auge.
Die Funktion str_replace auf einen String und nicht auf das _ganze_ Array ($testa) anwenden.
Was aber zumindest seit PHP 4.0.5 möglich ist:
As of PHP 4.0.5, every parameter in str_replace() can be an array.
Einen schönen Dienstag noch.
Gruß, Ashura
und wie das möglich ist. und es ist (eigentlich) wesentlich schneller als
foreach($testa AS $testname=>$testvalue)
$testa[$testname]=str_replace('_aaa','_bbb',$testvalue);
aber das tut nichts zur sache.
weiß denn hier auch keiner, wie das pgänomen zu erklären ist, warum das so langsam wird und beim ersten mal nicht?
Hallo
Was aber zumindest seit PHP 4.0.5 möglich ist:
As of PHP 4.0.5, every parameter in str_replace() can be an array.
Gut, hätte mal vorher nachschauen sollen. Gesagt, getun getan getätet ...
Da steht auch:
If subject is an array, then the search and replace is performed with every entry of subject, and the return value is an array as well.
Das trifft auf diesen Fall zu. Allerdings wird das durch die Schleifen unnötig oft getan. Wenn str-replace von sich aus das veränderte Array zurückgibt, ist die Ursache für das Einschlafen wohl in der unnötigen Schleife zu suchen. Ich zitiere mal:
for($i=0;$i<10000;$i++)
{
$ts=time();echo ".";flush();
for($j=0;$j<1000;$j++)
$test=str_replace('aaa','bbb',$testa);
$ts_=$ts_+(time()-$ts);
$ts=time();
if (bcmod($i,100)==0)
{
echo '<br>'.$ts_.'<br>';
$ts_=0;
}
}
10.000 (in Worten: zehntausend) mal wird die Funktion str_replace aufgerufen, um 'aaa' durch 'bbb' zu ersetzen. Sollte man sich da nicht schonmal Gedanken um den zugewiesenen Speicher gemacht haben?
Außerdem steckt da noch eine Schleife drin (for($j=0;$j<1000;$j++)
), die ohne Anweisung bleibt.
Tschö, Auge
ob das script sinn macht, ist ja nicht der springende punkt.
es soll ja nur gezeigt werden, warum ich zu der aussage komme, dass str_replace mein script (nein, nicht dieses - ein anderes... aber das genannte auch!) bremst.
hab von garbage collector gehört, der scheinbar anspringt bei der ausführung des scriptes.
aber ich frage mich oder besser euch, warum er das beim 2., 3. n-ten mal tut aber nicht beim ERSTEN mal. denn beim ersten durchlauf ist das script ja wie gesagt extrem schnell. ab dann nicht mehr.
ok, wenn es ein memory usage problem ist, dann brauch ich irgendne lösung, um den cache, den die str_replace funtion in anspruch nimmt, zu leeren vor/nach ausführung des befehls.
aber wie?
Hallo,
vielleicht wäre es besser, wenn man sich das eigentliche Script ansehen könnte.
Gruß aus Berlin!
eddi
Liebes Auge,
Du sagtest etwas zu diesem Code:
for($i=0;$i<10000;$i++)
{
$ts=time();echo ".";flush();
for($j=0;$j<1000;$j++)
$test=str_replace('aaa','bbb',$testa);
$ts_=$ts_+(time()-$ts);
$ts=time();
if (bcmod($i,100)==0)
{
echo '<br>'.$ts_.'<br>';
$ts_=0;
}
}
>
> Außerdem steckt da noch eine Schleife drin (`for($j=0;$j<1000;$j++)`{:.language-php}), die ohne Anweisung bleibt.
ich möchte Dir hier widersprechen: for (...) Anweisung; bewirkt, dass "Anweisung" in jedem for-Schleifen-Durchlauf ausgeführt wird. Es braucht bei einer einzigen Anweisung keine geschweiften Klammern wie bei einem ganzen Anweisungs\_block\_. Deshalb wird in jedem der 10000 (zehnTAUSEND) Schleifendurchgänge (mit $i als Index) 1000x (tausendmal - mit $j als Index) die str\_replace-Funktion ausgeführt, sodass wir auf die lächerliche Summe von 10 000 000 (zehn Millionen) str\_replace-Ausführungen kommen (und die auf ein Array!).
Ich schreibe einmal obigen Code mit anderen Einrückungen, dann wird es besser sichtbar:
~~~php
for($i=0;$i<10000;$i++)
{
$ts=time();echo ".";flush();
for($j=0;$j<1000;$j++)
$test=str_replace('aaa','bbb',$testa);
$ts_=$ts_+(time()-$ts);
$ts=time();
if (bcmod($i,100)==0)
{
echo '<br>'.$ts_.'<br>';
$ts_=0;
}
}
Auch ich frage mich, wie jetzt da der Sinn erkennbar werden soll...
Liebe Grüße aus Ellwangen,
Felix Riesterer.
Hallo
Liebes Auge,
Du sagtest etwas zu diesem Code:
for($i=0;$i<10000;$i++)
{
...
}
> >
> > Außerdem steckt da noch eine Schleife drin (`for ($j=0;$j<1000;$j++)`{:.language-php}), die ohne Anweisung bleibt.
>
> ich möchte Dir hier widersprechen: for (...) Anweisung; bewirkt, dass "Anweisung" in jedem for-Schleifen-Durchlauf ausgeführt wird. Es braucht bei einer einzigen Anweisung keine geschweiften Klammern wie bei einem ganzen Anweisungs\_block\_.
Aha. Dass das auch ohne Block oder andere Markierungen (`for(...): ... endfor;`{:.language-php}) funktioniert, wusste ich nicht.
> Deshalb wird in jedem der 10000 (zehnTAUSEND) Schleifendurchgänge (mit $i als Index) 1000x (tausendmal - mit $j als Index) die str\_replace-Funktion ausgeführt, sodass wir auf die lächerliche Summe von 10 000 000 (zehn Millionen) str\_replace-Ausführungen kommen (und die auf ein Array!).
Bevor ich entdeckte, dass das von mir als zwingend vorausgesetzte Klammerpaar fehlte, war ich auch schon bei dieser Zahl. :-)
> Auch ich frage mich, wie jetzt da der Sinn erkennbar werden soll...
Offensichtlich eine [Demo](https://forum.selfhtml.org/?t=130803&m=845863).
Tschö, Auge
--
Die Musik drückt aus, was nicht gesagt werden kann und worüber es unmöglich ist zu schweigen.
(Victor Hugo)
[Veranstaltungsdatenbank Vdb 0.1](http://termindbase.auge8472.de/)
Hallo,
Du wirst nichts schnelleres in PHP finden als str_replace(). Zu Deinem Testscript ist erstmal soweit nichts zu sagen, als das zehnmillionenmal eine Funktion aufgerufen wird. Dies dauert selbstverständlich.
Inwiefern die darin ermittelte Zeit eine Relevanz in Dein importscript hat, läßt sich von unserer Warte aus nicht überprüfen.
Gruß aus Berlin!
eddi
hier nochmal das script und unten das ergebnis auf meinem server.
habe festgestellt, dass das nicht auf jedem server so ist.
fall jemand weiß, welche einstellung schuld daran hat -> bitte bescheid sagen: garbage collector memory limit hab ich mir sagen lassen. aber ka, wie mans umstellt...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<?
$testa = array();
$testa[]='aaaaaaaaaaaaaaaaaaaaaaaaa';
$testa[]='bbbbbbbbbbbbbbbbbbbbbbbbb';
$testa[]='ccccccccccccccccccccccccc';
$testa[]='aaaaaaaaaaaaaaaaaaaaaaaaa';
$testa[]='bbbbbbbbbbbbbbbbbbbbbbbbb';
$testa[]='ccccccccccccccccccccccccc';
$testa[]='aaaaaaaaaaaaaaaaaaaaaaaaa';
$testa[]='bbbbbbbbbbbbbbbbbbbbbbbbb';
$testa[]='ccccccccccccccccccccccccc';
$testa[]='aaaaaaaaaaaaaaaaaaaaaaaaa';
$testa[]='bbbbbbbbbbbbbbbbbbbbbbbbb';
$testa[]='ccccccccccccccccccccccccc';
echo memory_get_usage()."<- memory usage before starting loop with limit at: ".ini_get('memory_limit')."<br>";flush();
for($i=0;$i<4;$i++)
{
$tstart = microtime(true);
for($j=0;$j<100000;$j++)
$testa=str_replace('_aaa','bbb',$testa);
echo microtime(true)-$tstart.' -memory usage: '.memory_get_usage()."<br>";flush();
flush();
}
?>
16432<- memory usage before starting loop with limit at: 8M
-0.089416 -memory usage: 36480
0.497955 -memory usage: 36480
-0.508495 -memory usage: 36480
0.493202 -memory usage: 36480
Hallo,
was soll die Zahlenreihe 1 bis 24 darstellen?
16432<- memory usage before starting loop with limit at: 8M
-0.089416 -memory usage: 36480
0.497955 -memory usage: 36480
-0.508495 -memory usage: 36480
0.493202 -memory usage: 36480
wie Du selbst sehen kannst, wird der Arbeitsspeicher innerhalb der Ausführung der Schleifer nicht mehr verändern. Was willst Du jetzt also mit garbage collector memory limit?
Warum Du negative Ergebnisse bei der Berechnung der Geschwindigkeit erhältst, ist aufgrund Deiner mangelhaften Mitarbeit (z. B. in Form von Versionsangaben PHPs, Angabe zum Webserver, etc.) zur Klärung des Problems spekulativ.
Jedenfalls ist nicht zu erkennen, wo Du bei 100.000 Durchläufen innerhalb von einer halben Sekunde auf einem meiner Systeme mit der Geschwindigkeit von str_replace() Probleme hast. Du wurdest von mir gebeten, das tatsächlich problematische Script für eine Durchsicht zugängig zu machen, aber auch hier verweigerst Du die Mitarbeit.
Da kann man wirklich bloß noch "hilfe!" sagen ;)
Gruß aus Berlin!
eddi
gudn tach!
der erste durchgang geht schnell von statten. aber dann dauert es manchmal sogar 10x länger!
was genau verstehst du unter dem ersten durchgang? (wo faengt der an und wo hoert er auf?)
hierzu das schlampig geschriebene demonstrationsbeispiel:
wenn ich das im cli ausfuehre, wird da staendig <br>6<br> und <br>7<br> ausgegeben (mit vielen punkten dazwischen).
prost
seth
Hi steffi,
hab nun lange versucht, herauszufinden, warum eines meiner import-scripte immer langsamer wird. nun scheine ich das time lag gefunden zu haben. es heißt str_replace(array())!
der erste durchgang geht schnell von statten. aber dann dauert es manchmal sogar 10x länger!
Weil str_replace() im ersten Durchgang alle "aaa" ersetzt hat, findet es in allen folgenden Durchgängen natürlich keine mehr. Wenn das Suchen intern zeitaufwändiger ist als das Ersetzen, könnte sich so der Zeitunterschied erklären.
hierzu das schlampig geschriebene demonstrationsbeispiel:
<?
set_time_limit(0);
$ts_=0;
$testa[]='aaaaaaaaaaaaaaaaaaaaaaaaa';
$testa[]='bbbbbbbbbbbbbbbbbbbbbbbbb';
$testa[]='ccccccccccccccccccccccccc';
$testa[]='aaaaaaaaaaaaaaaaaaaaaaaaa';
$testa[]='bbbbbbbbbbbbbbbbbbbbbbbbb';
$testa[]='ccccccccccccccccccccccccc';
$testa[]='aaaaaaaaaaaaaaaaaaaaaaaaa';
$testa[]='bbbbbbbbbbbbbbbbbbbbbbbbb';
$testa[]='ccccccccccccccccccccccccc';
$testa[]='aaaaaaaaaaaaaaaaaaaaaaaaa';
$testa[]='bbbbbbbbbbbbbbbbbbbbbbbbb';
$testa[]='ccccccccccccccccccccccccc';
for($i=0;$i<10000;$i++)
{
$ts=time();echo ".";flush();
for($j=0;$j<1000;$j++)
$test=str_replace('aaa','bbb',$testa);
$ts_=$ts_+(time()-$ts);
$ts=time();
if(bcmod($i,100)==0)
{
echo '<br>'.$ts_.'<br>';
$ts_=0;
}
}
?>was kann ich tun, damit jeder durchgang so schnell geht wie der erste?
In dem speziellen Fall: Bei jedem Ersetzvorgang ein Array bereitstellen, in dem so viele 'aaa' vorhanden sind wie $testa vor Beginn der Schleifen. Guckst du mal hier:
<?php
set_time_limit(0);
// nur zum Zeit-Messen ...
function calculate_runtime(
$time = FALSE // NUMERIC: Ein gültiger Zeitstempel
){
list($usec, $sec) = explode(' ', microtime());
if(FALSE === $time) return ( (float)$sec + (float)$usec ); // Startzeit zurueckgeben
if( !is_numeric($time) ) return( $this->return_error(E_WARNING, 'parameter has to be of NUMERIC type') );
return( (float)$sec + (float)$usec - $time ); // uebergebene Zeit von aktueller Zeit abziehen
}
$ts_=0;
$testa[]='aaaaaaaaaaaaaaaaaaaaaaaaa';
$testa[]='bbbbbbbbbbbbbbbbbbbbbbbbb';
$testa[]='ccccccccccccccccccccccccc';
$testa[]='aaaaaaaaaaaaaaaaaaaaaaaaa';
$testa[]='bbbbbbbbbbbbbbbbbbbbbbbbb';
$testa[]='ccccccccccccccccccccccccc';
$testa[]='aaaaaaaaaaaaaaaaaaaaaaaaa';
$testa[]='bbbbbbbbbbbbbbbbbbbbbbbbb';
$testa[]='ccccccccccccccccccccccccc';
$testa[]='aaaaaaaaaaaaaaaaaaaaaaaaa';
$testa[]='bbbbbbbbbbbbbbbbbbbbbbbbb';
$testa[]='ccccccccccccccccccccccccc';
$start = calculate_runtime();
for($i=0;$i<10000;$i++)
{
//$ts=time();echo "."; //flush();
for($j=0;$j<1000;$j++)
$testb = $testa;
$test=str_replace('aaa','bbb',$testb);
/*
$ts_=$ts_+(time()-$ts);
$ts=time();
if(bcmod($i,100)==0)
{
echo '<br>'.$ts_.'<br>';
$ts_=0;
}
//*/
}
printf('<hr />dauer(%s)', calculate_runtime($start) );
?>
MffG
EisFuX
Hallo,
Weil str_replace() im ersten Durchgang alle "aaa" ersetzt hat, findet es in allen folgenden Durchgängen natürlich keine mehr.
for($i=0;$i<10000;$i++)
{
for($j=0;$j<1000;$j++)
$test=str_replace('aaa','bbb',$testa);
}
das ist Unsinn. $testa
wird zu keiner Zeit überschrieben. Jedem Schleifendurchlauf liegen die _selben_ Daten zugrunde.
Gruß aus Berlin!
eddi
Hallo eddi,
das ist Unsinn.
$testa
wird zu keiner Zeit überschrieben. Jedem Schleifendurchlauf liegen die _selben_ Daten zugrunde.
Schimpf und Schande über mich -- da ist mir wohl beim Hin- und Herkopieren was durcheinander geraten. Klar, str_replace() überschreibt ja nichts, sondern gibt das Ergebnis der Ersetzungsvorgangs zurück.
MffG
EisFuX