mmofacts.com

Werden Parameter in PHP Methoden auf einem Stack übergeben?

gepostet vor 17 Jahre, 3 Monate von DrakeL
Etwas was mehr in der Theorie interessant ist, aber in der Praxis wenig Unterschied in der Performance machen sollte (aber einen Unterschied macht, ohne dass man viel ändern muss).
Wenn ich in PHP einer Methode Parameter übergebe, werden diese intern dann auf einen Stack gelegt wovon man Sie dann wieder abrufen muss?
Dann wäre folgende Variante langsamer:
public function __construct($first, $second)

{
$this->first = $first;
$this->second = $second;
}
Hier muss erst $first auf den Stack gelegt werden, dann $second. Anschließend wird $second runter genommen um auf $first zuzugreifen, danach $second wieder drauf gelegt und anschließend $second runtergeholt.
im Vergleich zu dieser:
public function __construct($first, $second)

{
$this->second = $second;
$this->first = $first;
}
Hier würde $first und dann $second auf den Stack gelegt. In der Methode dann erst $second runter genommen und danach $first runter genommen.
Daher falls die Parameter auf einem Stack gelagert werden würde, wäre letzteres sehr viel effizienter.
gepostet vor 17 Jahre, 3 Monate von None
und mit referenzen arbeiten, hätte das auch vorteil? ich hab das mal bei DAOs in PHP gemacht, wo ich die Klasse als referenz übergeben habe
gepostet vor 17 Jahre, 3 Monate von DrakeL
In PHP 4 macht es denk ich schon Sinn wenn Objekte mit mehreren Membervariablen hast, da das Objekt nicht komplett kopiert werden muss, sondern nur seine Adresse.
In PHP 5 wird jedes Objekt standardmäßig als Referenz übergeben (ganz wichtig, wenn man PHP 4 Anwendungen auf PHP 5 portieren will!).
PS: Begrifflichkeiten finde ich wichtig, von daher man kann keine Klassen übergeben, sondern nur Objekte von einer Klasse.
gepostet vor 17 Jahre, 3 Monate von None
Das hab ich nicht gewusst, das Objekte standartmäßig als Referenz in PHP 5 übergeben werden. Ich schreibe immer:
class UserDao implements IUserDao

{
public function checkUser(User &$user)
{
// tu was
}
}
?>
gepostet vor 17 Jahre, 3 Monate von Nuky
Das & ist in PHP 5 deprecated; Schalt mal E_NOTICE ein, bei PHP 6 gibt das nen E_STRICT.
@DrakeL:
Das weiß ich diesmal nichtmal, aber soviel kann ich dir - selbst als absolutes Perfomance-übertreib-Viech, wie ich bin - sagen:
Das ist komplett egal. ^^
gepostet vor 17 Jahre, 3 Monate von DrakeL
Hab das noch nie gemacht, aber wenn das so funktioniert ist es auf jeden Fall unnötig, da es keinen Unterschied macht.
Da sowas schnell zu Fehlern führen kann, vor allem wenn Objekte veränderst in den Methoden und nicht weißt, dass es das Objekt außen auch betrifft, musste an manchen Stellen halt aufpassen (wobei es mir bisher mehr Vorteile als Nachteile gebracht hat).
Ist eines der wenigen Dinge, die sich grundlegend mit PHP 5 geändert haben (und zu PHP 4 nicht mehr unbedingt kompatible sind), sollte man aber dann auch umso besser wissen.
gepostet vor 17 Jahre, 3 Monate von DrakeL
Original von Nuky
Das & ist in PHP 5 deprecated; Schalt mal E_NOTICE ein, bei PHP 6 gibt das nen E_STRICT.

PHP 6 ist aber nicht stabil schon veröffentlicht, oder? Nicht dass ich da was verpasse ^^
Original von Nuky

Das weiß ich diesmal nichtmal, aber soviel kann ich dir - selbst als absolutes Perfomance-übertreib-Viech, wie ich bin - sagen:
Das ist komplett egal. ^^
Deswegen hab ich auch am Anfang geschrieben, dass es mehr theoretisch ist. Aber man will ja dazulernen.
Aber wieso sollte man darauf nicht achten, wenn es ohne Probleme änderbar ist und zumindest ein bisschen Performance spart (viel Kleinmist macht ja bekanntlich auch groß ^^). Und wenn man sehr viele Methodenzugriffe hat und wie ich immer von links nach rechts arbeitet (also genau andersrum) dürfte sich das vielleicht sogar bemerkbar machen (also paar % vielleicht ^^).
gepostet vor 17 Jahre, 3 Monate von Agmemon
Also wie es nun genau in PHP gemacht wird, kann ich Dir nicht sagen. Aber mit einem Semester Erfahrung in Compilerbau würde ich mal behaupten, es ist egal, in welcher Reihenfolge Du es schreibst. Der Interpreter sorgt schon selbst für die Optimierung.
Wird als Zwischencode z.B. die Postfix-Notation verwendet, sorgt der Interpreter dafür, das Werte, welche zusammen gehören, direkt zusammen auf dem Stack liegen. So wie man das bei den alten HP Taschenrechnern hatte.
Aber ich will jetzt hier keine Abhandlung über die Compilerbau-Theorie abfassen.
Daher zum Abschluss noch ein Zitat, was hier ganz gut passt:
"We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil." (Donald Knuth, Code Complete, Page 594)
gepostet vor 17 Jahre, 3 Monate von Nuky
Ich habe nachgedacht, und mir ist eingefallen da das sowieso ja in einer Virtual Machine läuft..
Compilerbau hatte ich zwar noch nicht, aber wir haben einen Prozessor simulieren müssen - ziemlich vergleichbar mit der PHP - Engine.
PHP hat keinen Compiler in der Form, der das nachoptimieren könnte/müsste, sondern alle Variablen die du anlegst sind Objekte, die sowieso alle im Memory liegen müssten - daher sollte es wirklich egal sein, in welcher Reihenfolge du machst.
Abgesehen davon:
"When you are an experienced Coder: Don't Optimize.
When you are an expert Coder: Don't do it yet."
gepostet vor 17 Jahre, 3 Monate von Agmemon
Im Bereich Compilerbau ist ein Compiler ein wenig was anderes, als man als Entwickler darunter versteht. Hat lange gedauert, bis ich das verstanden hatte.
Ein Compiler ist die Komponente, welche die Ergebnisse des Parsers entgegen nimmt und in eine Form bringt, die interpretiert werden kann. Ob das Ergebnis des Compilers direkt interpretiert wird, ein Zwischencode erstellt wird (z.B. Postfix, n-Adresscode, Bytecode) oder ausführbarer Binärcode, ist dabei eigentlich egal.
Die Objekte liegen dabei im Speicher, das ist klar. Aber innerhalb des Interpreters wird zur Abarb eitung so eine Art Pseudospeicher in Form eines Stacks verwendet. Und ich denke, dass meinte DrakeL.
gepostet vor 17 Jahre, 3 Monate von DrakeL
Wenn etwas ohne Probleme zu ändern geht und etwas Performance sparen kann, dann änder ich sowas gerne.
Wenn es wirklich egal ist und keinerlei Unterschied macht, klar dann würde ich es auch nicht ändern. Aber wenn es etwas Performance bringt, wieso nicht, spricht nichts dagegen. Bzw. dann wäre man schlauer und könnte es in Zukunft immer so machen.
Also wissen tut es keiner genau oder?
Dann mach ich mal nen Extremtest und probier beides aus mit "paar" Aufrufen. ^^
gepostet vor 17 Jahre, 3 Monate von DrakeL
Normale Aufrufe: 1.75332903862
Optimierte Aufrufe: 2.1756989955902
Mmh, unerwartetes Testergebnis. In falscher Reihenfolge waren die Aufrufe immer schneller (habe es rund 10 mal durchlaufen lassen) als in für den Stack optimierter Reihenfolge. Ich glaub PHP arbeitet anders rum. ^^
Falls jemand nachvollziehen will:
   function a($first, $second)

{
$var = $first;
$var = $second;
}

function b($first, $second)
{
$var = $second;
$var = $first;
}

$executes = 1000000;

$start = microtime(true);
for($i = 0; $i <= $executes; ++$i)
{
a('first', 'second');
}
$normal = microtime(true) - $start;
print 'Normale Aufrufe: ' . $normal . '
';

$start = microtime(true);
for($i = 0; $i <= $executes; ++$i)
{
b('first', 'second');
}
$optimize = microtime(true) - $start;
print 'Optimierte Aufrufe: ' . $optimize . '
';
?>
PS: Hat aber immerhin immer einen Unterschied von ca. 20% gehabt. Fällt zwar nicht auf (wenn man nicht grad über 10k - 100k Methodenaufrufe hat), aber ich finde es trotzdem interessant die Performance auch im kleinen Maßstab zu verbessern. ^^
gepostet vor 17 Jahre, 3 Monate von Bringer
ich hab obiges script mal kurz ausgeführt,
auf dem "normalen" webserver bekam ich in 3 versuchen:
Normale Aufrufe: -0.143124
Optimierte Aufrufe: 0.702802
Normale Aufrufe: 0.841757
Optimierte Aufrufe: -0.3091
Normale Aufrufe: 0.23333
Optimierte Aufrufe: -0.221909
Natürlich spielt die aktuelle auslastung dabei eine nicht unerhebliche rolle weshalb ich einfach noch 3mal denselben prozess ausgeführt habe.
Normale Aufrufe: -0.030571
Optimierte Aufrufe: 0.870309
Normale Aufrufe: -0.660603
Optimierte Aufrufe: 0.939709
Normale Aufrufe: 0.605291
Optimierte Aufrufe: -0.109945
auf dem lokalen apache dagegen lief das ganze ohne last noch mehr außer rand und band, weshalb ich mich frage mit welcher php version du getestet hast?
mein webserver läuft mit php 4.3.9 während ich meinen apache mit 5.0.2 bewegen lasse.
Die resultierenden unterschiede erscheinen mir als "Welten"
gepostet vor 17 Jahre, 3 Monate von DrakeL
hö, wie kommst du auf nen Minuswert? Zeitdifferenzen können nicht minus sein, außer ich hab was falsches rausgelöscht bevor ich es hier gepostet hab. ^^
Ich hab die aktuelle 5er PHP Version. Test war nicht lokal gemacht, sondern auf meinem Webspace, aber hat immer das gleiche Ergebnis gebracht, in gleicher Reihenfolge abgefragt wie in der Parameterliste angegeben war immer schneller.
gepostet vor 17 Jahre, 3 Monate von Bringer
Original von DrakeL
hö, wie kommst du auf nen Minuswert? Zeitdifferenzen können nicht minus sein, außer ich hab was falsches rausgelöscht bevor ich es hier gepostet hab. ^^

Genau hier stieg mein eher ungeuebtes hirn aus... ich bin weder in php/sql noch in perl, phython oder erlang auch nur annaehernd geuebt, aber fuer ein verwundertes schmunzeln reichten meine kenntnisse noch aus...
Ich hab einfach deinen code 1=1 uebernommen und ausgeführt, was dabei rauskam siehst du ja oben.
PHP 4.3.9 hat es so entstellt, PHP 5.0.2 (lokal) lieferte mir dagegen in ebenfalls 6 versuchen einen mittelwert von:
function a : 1.2715945
function b : 1.85626
Original von DrakeL

Ich hab die aktuelle 5er PHP Version. Test war nicht lokal gemacht, sondern auf meinem Webspace, aber hat immer das gleiche Ergebnis gebracht, in gleicher Reihenfolge abgefragt wie in der Parameterliste angegeben war immer schneller.
Dann muss ich mich nochmehr verwundern...
ich habe die 6 tests im vorherigen post innerhalb von knapp 2 min ausgeführt, die werte in obigem posting entsprechen genau der ausgabe
nein ich muss das als marketingfuzzi nicht verstehen oder?
edit: ach ja...
testet selbst, der letzte versuch mit PHP 4 erbrachte:
Normale Aufrufe: -0.598396
Optimierte Aufrufe: 0.595489
wolvgames.net/opt.php
gepostet vor 17 Jahre, 3 Monate von duschendestroyer
hab grad aus langerweile den gleichen benchmark mit ruby gemacht...
und es entsteht ein ähnliches ergebnis
also optimiert langsamer als normal
gepostet vor 17 Jahre, 3 Monate von DrakeL
Original von Bringer
Genau hier stieg mein eher ungeuebtes hirn aus... ich bin weder in php/sql noch in perl, phython oder erlang auch nur annaehernd geuebt, aber fuer ein verwundertes schmunzeln reichten meine kenntnisse noch aus...

Aktuelle Systemzeit in Mikrosekunden holen
Die Methodenaufrufe durchführen
Die vorherige Systemzeit von der jetzigen abziehen
Wenn du da Minuszahlen raus bekommst heißt das, deine Systemzeit zählt Rückwärts, da nach dem ausführen deine Systemzeit weiter in der Vergangen liegt als danach. Das geht gar nicht, also irgendwas läuft da schief. ^^
Ich hab noch ein paar Durchgänge gemacht und jetzt annähernd die selben Werte für beide Methodenaufrufe bekommen. Also scheint es doch egal zu sein.
gepostet vor 17 Jahre, 3 Monate von HSINC
unter php4 liefert mircotime andere werte als unter php5. bzw vom aufbau her andere werte. deswegen das minus.
gepostet vor 17 Jahre, 3 Monate von Amun Ra
D:\Apache\bin>ab -n 100000 localhost/test.php ( test2.php )
Ein Request hat bei mir im Schnitt immer zwischen 1,51 und 1,53 ms gedauert.
Also ich kann da keinen Unterschied erkennen und würd sagen,
auch wenn so Spielereien Spass machen,
mach dir um andere Sachen Gedanken.
gepostet vor 17 Jahre, 3 Monate von raufaser
Ja schau mal einer an:
Bei den ersten Aufrufen:
Normale Aufrufe: 7.05044388771
Optimierte Aufrufe: 5.12841296196
Später dann:
Normale Aufrufe: 4.99675798416
Optimierte Aufrufe: 5.32641506195
Mein Setup:
lighttpd + fastcgi + php 5 (mit eaccelerator)
Scheint da anders zu laufen.
Gruß,
Marc
gepostet vor 17 Jahre, 3 Monate von SpeedyGTD
Ich hab das Script auch mal getestet, allerdings in 2 ausführungen, ein mal die Originalversion von DrakeL und eine von mir abgeänderter (Quellcode siehe unten).
nach ca 20 durchläufen kam ich zu dem Ergebnis, dass die erste For-Schleife immer schneller durchläuft wie die zweite, es kam lediglich zwei mal zu umgekehrten ergebnissen (das die erste langsamer läuft), da dies aber bei beiden versionen ein mal auftrat, gehe ich davon aus, dass das ein auslastungsproblem vom server war.
   function b($first, $second)

{
$var = $second;
$var = $first;
}
function a($first, $second)
{
$var = $first;
$var = $second;
}

$executes = 1000000;

$start = microtime(true);
for($i = 0; $i <= $executes; ++$i)
{
b('first', 'second');
}
$optimize = microtime(true) - $start;
print 'Optimierte Aufrufe: ' . $optimize . '
';

$start = microtime(true);
for($i = 0; $i <= $executes; ++$i)
{
a('first', 'second');
}
$normal = microtime(true) - $start;
print 'Normale Aufrufe: ' . $normal . '
';
?>
gepostet vor 17 Jahre, 3 Monate von TheUndeadable
Nur weil ein Parameter auf einem Stack liegt, heißt es lang noch nicht, dass die CPU nicht direkt auf ein darunterliegendes Element zugreift
<- ESP (Meine, dass er das war)
Element1 (4 Bytes)
Element2 (8 Bytes)
Element3 (4 Bytes)
Der Computer greift nun auf Element 2 zu in dem er einfach vom ESP 12 Bytes abzieht (bzw 4 Bytes dazuaddiert, da ein Stack bei x86er-Technologien von oben kommt). Es muss für den direkten Zugriff kein Stack umgebaut werden.
Es ist nur möglich vom Stack die Elemente von oben zu entnehmen bzw nur oben draufzulegen. [Von dreckigen Tricks zur Laufzeitbeeinflussung mal abgesehen]
Warum die erste For-Schleife evtl schneller läuft? Keine Ahnung, ich vermute mal, dass PHP noch den ersten $second-Wert in irgendeinem Cache hat und bei umgekehrter Reihenfolge keine Umordnung der Befehle zur Verbesserung der Performance erledigt.
In 2 kompilierten Sprachen (C#, C++) habe ich keinen Unterschied festgestellt.
> aber ich finde es trotzdem interessant die Performance auch im kleinen Maßstab zu verbessern.
Interessant: Ja
Notwendig: Vergebene Liebesmühe. Ich würde lieber die Zeit darin investieren SQL-Queries und externe Datenzugriffe zu minimieren. Weiterhin evtl die Komplexität von Algorithmen (von O(n^2) auf O(n) z.B.) reduzieren, soweit du solche Algorithmen hast. Ich würde solche Optimierungen, wie du sie hier zeigst, nur bei dicken Schleifendurchgängen durchführen, da bei der nächsten PHP-Version schon wieder alles umsonst sein kann.
BTW: Nachtrag:
Es kann sein, dass PHP die erste Anweisung killt (Laufzeitoptimierung) und der zweite String 'second' etwas länger ist als der erste. Ist aber nur eine wage Vermutung. Versucht mal die Strings gleich lang zu machen.
Und wichtig:
Tauscht auch mal die Aufrufe. Also die untere For-Schleife nach oben und umgekehrt. Ist immer noch ein Effekt messbar (der müsste dann umgekehrt sein)
gepostet vor 17 Jahre, 3 Monate von SpeedyGTD
Original von TheUndeadable
...
Und wichtig:
Tauscht auch mal die Aufrufe. Also die untere For-Schleife nach oben und umgekehrt. Ist immer noch ein Effekt messbar (der müsste dann umgekehrt sein)

genau das hab ich doch gemacht, siehe das posting vor deinem. Ich hab allerdings auch noch zusätzlich die funktion b nach oben geschoben, das dürfte aber wohl am wenigsten ausmachen.
gepostet vor 17 Jahre, 3 Monate von TheUndeadable
Ah, ok, vergebe mir bitte, habe nur die erste Seite gelesen...
Vielleicht dauert ja das Erzeugen der Variablen $i so lang ;-)
gepostet vor 17 Jahre, 3 Monate von Nuky
Ich sag wenn du bei 1 mio Aufrufen einen Unterschied von 0.3 Sec hast, dann spar dir die 0,0000003 Sec Optimierung.
Da bringt dir ja schon ein LIMIT 1 in jedem SELECT wo du nur eine Spalte willst schon ein vielfaches..
gepostet vor 17 Jahre, 3 Monate von DrakeL
Original von DrakeL
Etwas was mehr in der Theorie interessant ist, aber in der Praxis wenig Unterschied in der Performance machen sollte (aber einen Unterschied macht, ohne dass man viel ändern muss).

Mir ist klar dass diese Optimierung in der Praxis kaum etwas bewirken sollte. Aber darum ging es mir in erster Linie nicht, sondern ich wollt einfach mal in der Theorie wissen, ob das so ist und es dann vielleicht berücksichtigen (wieso soll es sinnlos sein das zu berücksichtigen, wenn es einen Vorteil bringt, der zwar sehr klein ist, aber keinerlei Nachteile birkt?).
Dass andere Dinge wie SQL Statements und Algorithmen effektiver zu optimieren sind ist mir sehr klar, nicht umsonst hab ich meine Tabellenklasse erweitert, dass Sie nicht immer ein "select *" machen, sondern ich die Spalten mitgebe und ähnliche Neuerungen.
PS: Hab bei zwei Threads scho gesagt, dass es mir mehr um die Theorie geht, und wenn ich das schreib dann isses auch so und für die Praxis eigentlich völlig irrelevant.
aber mein Hauptziel bei der Entwicklung ist nicht das fertige Spiel (das ist nur ein Extra), sondern die Grenzen von PHP kennen lernen anhand eines größeren Projektes und dabei noch etwas zu lernen (Hey, wie geil, hab gestern mal wieder viele neue Dinge gelernt mit neuem Buch: Entwurfsmuster von Kopf bis Fuß, sollte wirklich jeder besitzen ^^). Das zweite Hauptziel des Projektes ist es mir eine Referenz zu schaffen, mit der ich mich später einmal bewerben kann, deswegen achte ich sehr auf sauberen flexiblen Quellcode und etwas weniger auf Performance oder eine schnelle Entwicklung.
gepostet vor 17 Jahre, 3 Monate von n26
Normale Aufrufe: 2.1295440196991
Optimierte Aufrufe: 2.2708158493042
Normale Aufrufe: 2.0715827941895
Optimierte Aufrufe: 2.4179670810699
Die for Schleifen mal vertauscht:
Optimierte Aufrufe: 2.1419107913971
Normale Aufrufe: 2.1686890125275
Optimierte Aufrufe: 2.1714198589325
Normale Aufrufe: 2.1601130962372
Dann habe ich aus interesse noch versucht was passiert wenn ich bei der 2. for Schleife statt wieder dem $i mal ein $n verwende:
Normale Aufrufe: 2.131208896637
Optimierte Aufrufe: 2.2291309833527
Normale Aufrufe: 2.118880033493
Optimierte Aufrufe: 2.2080450057983
Getestet auf nem IIS6 + PHP Version 5.2.2
gepostet vor 17 Jahre, 3 Monate von Bringer
Original von HSINC
unter php4 liefert mircotime andere werte als unter php5. bzw vom aufbau her andere werte. deswegen das minus.

jepp, das wars... ich hab es gerade im 5er nochmals nachvollzogen und bekam nun auch die erwarteten werte...
auch hier war optimiert die langsamere lösung

Auf diese Diskussion antworten