Performance bei foreach schleife?

SantaCruze

Erfahrenes Mitglied
Hallo Zusammen. Und zwar habe ich ein kleines Problem. Ich lasse eine Foreach schleife innerhalb eines scripts laufen welches aber auch mit Smarty gekoppelt ist. Nun habe ich folgendes Problem, die Schleife scheint sehr performance lastig zusein, sprich teilweise hab ich nen Seitenaufbau bei 20 Objekten von 1.5 sekunden. Kann man die Schleife irgendwie umschreiben damit sie schneller läuft oder durch eine andere Schleifenart ersetzen? Habe vorher in nem Schleifen Benchmark gelesen das Foreach Schleifen teilweise um ein vierfaches langsamer sind als andere. Hier der Code

PHP:
$j=0;
    foreach($buildlist as $id => $lev)
    {
      $smarty_buildlist[$j]['id'] = $id;
      $smarty_buildlist[$j]['name'] = $db->building_get_name($id);
      $smarty_buildlist[$j]['level'] = $lev-1;
      $smarty_buildlist[$j]['buildlevel'] = $lev;
      $smarty_buildlist[$j]['need_res'] = $db->formatted_building_get_costs($id,$lev);
      $smarty_buildlist[$j]['need_time'] = $db->formatted_building_get_time($id,$lev,$_SESSION["coords"]);
      $smarty_buildlist[$j]['color'] = "#FFFF00";
      $smarty_buildlist[$j]['image'] = $db->building_get_image($id);
      if($db->buildings_can_build($_SESSION["coords"],$id))
      {
        $smarty_buildlist[$j]['color'] = "#00FF00";
      }
      else
      {
        $smarty_buildlist[$j]['color'] = "#FF0000";
      }
      $db->reinit();
      $taskid = $db->tasks_id_building_on_build($_SESSION["coords"],$id);
      if($taskid != -1)
      {
        $smarty_buildlist[$j]['onbuild'] = 1;
   $db->reinit();
   $smarty_buildlist[$j]['resttime'] = $db->tasks_endtime($taskid)-time();
   $db->reinit();
   $smarty_buildlist[$j]['resttime_formatted'] = date("H:i:s",$smarty_buildlist[$j]['resttime']);
   $smarty_buildlist[$j]['color'] = "#FFFFFF";
   $somethingonbuild=1;
      }
      unset($db); $db = new cl_extended_database;
      $j++;
    }
 
Mein Vorschlag:
PHP:
$keys = array_keys($buildlist);
$count = count($keys);
for( $j=0; $j<$count; $j++ ) {
	$id =& $keys[$j];
	$lev =& $buildlist[$keys[$j]];
	$smarty_buildlist[$j] = array(
		'id'         => $id,
		'name'       => $db->building_get_name($id),
		'level'      => $lev-1,
		'buildlevel' => $lev,
		'need_res'   => $db->formatted_building_get_costs($id, $lev),
		'need_time'  => $db->formatted_building_get_time($id, $lev, $_SESSION["coords"]),
		'color'      => $db->buildings_can_build($_SESSION["coords"], $id) ? "#00FF00" : "#FF0000",
		'image'      => $db->building_get_image($id),
	);
	$db->reinit();
	$taskid = $db->tasks_id_building_on_build($_SESSION["coords"], $id);
	if( $taskid != -1 ) {
		$smarty_buildlist[$j]['onbuild'] = 1;
		$db->reinit();
		$smarty_buildlist[$j]['resttime'] = $db->tasks_endtime($taskid)-time();
		$db->reinit();
		$smarty_buildlist[$j]['resttime_formatted'] = date("H:i:s", $smarty_buildlist[$j]['resttime']);
		$smarty_buildlist[$j]['color'] = "#FFFFFF";
		$somethingonbuild = 1;
	}
	unset($db);
	$db = new cl_extended_database;
}
Sind die vielen „$db->reinit()“ und die Initiierung des „$db“-Objekt bei jedem Durchlauf eigentlich notwendig?
 
Ja da ich mit einer DB Klasse arbeite. Die Schleife die Du mir vorgeschlagen hast (@Gumbo) bringt eigentlich keinen merkbaren Performance gewinn. Die Werte der Ausgabe sind immernoch in fast dem gleichen bereich.
 
Zuletzt bearbeitet:
Hm ... also ich tippe mal das es daran liegt das du bei jedem Schleifendurchlauf eine weitere Instanz der db classe erstellst $db = new cl_extended_database;

Ich bin zur Zeit ein wenig raus was php und oop angeht, aber meiner Meinung nach würde es auch reichen die Datenbankclasse einmal vor der Schleife zu instanzieren. Jede Instanz die du von einer Klasse erstellst belastet den Arbeitsspeicher des Servers. Un bei einer schleife die evtl sehr sehr viele Durchläufe hat kann man sich ja vorstellen was da an Daten dann zusammenkommt.

MfG
blueX
 
Naja die Schleife hat normal 15 durchläufe, ich habe die auf 18 erweitert und ab dann fängt er ab und an zu stoppen. Das merkwürdige ist halt, das er es Local macht, sprich Online hab ich das noch net gestellt weil ich befürchte das es da auch auftritt.

Ich poste mal kurz das gesamte Script , dann kannst Du mir ja vielleicht sagen ob irgendwo was nicht richtig ist oder fehlt:

PHP:
  $db = new cl_extended_database;
  
  if(isset($_SESSION["id"]))
  {
    
    $id = $_SESSION["id"];
    $id_save = $id;

    if(!isset($_SESSION["coords"]))
    {
      $_SESSION["coords"] = $db->planets_get_coords($id);
    }
    require('resbar.inc.php'); 

    $cantbuild = -1;
    $db->reinit();
    $somethingonbuild=$db->tasks_somethingonbuild($_SESSION["coords"]);
    $db->reinit();
    if(isset($_GET['B'])&&$somethingonbuild==-1)
    {
      if($db->buildings_can_build($_SESSION["coords"],$_GET['B']))
      {
	$db->reinit();
        $level = $db->planets_building_level($_SESSION['coords'],$_GET['B']);	
	$userid = $id;
	//unset($db); $db = new cl_extended_database;
        $db->reinit();
	$endtime = time() + $db->building_get_time( $_GET['B'],($level+1),$_SESSION['coords']);
	//unset($db); $db = new cl_extended_database;
        $db->reinit();
        $db->tasks_building_build($_SESSION['id'],$_SESSION['coords'], $_GET['B'],($level+1),$endtime);
	$db->reinit();
	//echo "<br>in table!";
      }
      else
      {
        $cantbuild = $_GET['B'];
      }
    }
    if(isset($_GET['s']) && $somethingonbuild==1)
    {
      //stop task
      $db->reinit();
      $taskid = $db->tasks_id_building_on_build($_SESSION["coords"],$_GET['s']); 
      $db->task_kill($taskid);   
      $somethingonbuild=-1;   
    }
    unset($db); $db = new cl_extended_database;
    $buildlist = $db->planet_buildlist($_SESSION["coords"]);
    unset($db); $db = new cl_extended_database;
    $smarty_buildlist = array();
    $j=0;
    foreach($buildlist as $id => $lev)
    {
      $smarty_buildlist[$j]['id'] = $id;
      $smarty_buildlist[$j]['name'] = $db->building_get_name($id);
	  //$smarty_buildlist[$j]['image'] = $db->building_get_image($id);
      $smarty_buildlist[$j]['level'] = $lev-1;
      $smarty_buildlist[$j]['buildlevel'] = $lev;
      $smarty_buildlist[$j]['need_res'] = $db->formatted_building_get_costs($id,$lev);
      $smarty_buildlist[$j]['need_time'] = $db->formatted_building_get_time($id,$lev,$_SESSION["coords"]);
      $smarty_buildlist[$j]['color'] = "#FFFF00";
      if($db->buildings_can_build($_SESSION["coords"],$id))
      {
        $smarty_buildlist[$j]['color'] = "#00FF00";
      }
      else
      {
        $smarty_buildlist[$j]['color'] = "#FF0000";
      }
      $db->reinit();
      $taskid = $db->tasks_id_building_on_build($_SESSION["coords"],$id);
      if($taskid != -1)
      {
        $smarty_buildlist[$j]['onbuild'] = 1;
	$db->reinit();
	$smarty_buildlist[$j]['resttime'] = $db->tasks_endtime($taskid)-time();
	$db->reinit();
	$smarty_buildlist[$j]['resttime_formatted'] = date("H:i:s",$smarty_buildlist[$j]['resttime']);
	$smarty_buildlist[$j]['color'] = "#FFFFFF";
	$somethingonbuild=1;
      }
      unset($db); $db = new cl_extended_database;
      $j++;
    }

    $id = $id_save;
 
Hallo,

du hast uns immer noch nicht verraten, warum du das $db-Objekt nach jedem Schleifendurchlauf neu erstellst. Wieso ist das unbedingt notwendig?

Grüße,
Matthias
 
Du hast in dem Code an mehreren Stellen
PHP:
unset($db); $db = new cl_extended_database;
stehen.

Das ist eigendlich völlig un nötig. Es reicht wenn du das db Objekt einmal am Anfang instanzierst danach kannst du es bis zum Ende der Datei nutzen ..... du musst vor einem neuen Datensatz kein unset($db) machen und auch nicht die Klasse neu instanzieren .. das nimmt nur unnötige Performance. Einmal am Anfang reicht ... auch innerhalb der Schleife kannst du diese Zeile raus nehmen. Alles was du brauchst ist das
PHP:
$db = new cl_extended_database;
am Anfang der Datei.

Jedes mal wenn du eine neue Instanz der db Klasse erstellst wird auch eine neue Verbindung zur Datenbank her gestellt... Bei 18 Schleifen-durchläufen würde sich das Script 21 mal in der db einloggen.... das ist etwas viel würd ich sagen.

MfG
blueX
 
Also wenn ich

PHP:
$db = new cl_extended_database;
      $j++;

Die new_cl rausnehme läuft nix mehr. Sprich er spuckt hunderte Fehlermeldungen aus. Waru m ist mir klar, er berechnet immer nur einen Schleifendurchlauf und connected dann neu. Leider bringt es nichts, die cl nur an den Anfang zusetzen :( Dann findet die Schleife nichts mehr bzw. liefert keine Ergebnisse mehr. Wäre es möglich (und wenn ja wie) das ich die Schleife direkt so ansteuere an die DB, das er mir eine genaue ID Anzahl ausließt, ohne das er jedes mal neu die verbindung öffnet ?
 
Hmmm, also wenn du nur genau das rausgenommen hast was du gerade geschrieben hast, ist es klar, dass Fehlermeldungen kommen.
Es wird dann nämlich nach dem ersten Durchlauf unset($db) ausgeführt und danach nicht neu initialisiert und das $j++ brauchst du doch für dein Array...

nimm mal aus dem ursprünglichen Code nur das hier raus
PHP:
unset($db); $db = new cl_extended_database;
ich denke mal, dass du $db vor der Schleife schonmal definiert hast.
 
Zurück