Ankündigung

Einklappen
Keine Ankündigung bisher.

Lambda-Funktion und array_map/_filter gegen foreach

Einklappen

Neue Werbung 2019

Einklappen
X
  • Filter
  • Zeit
  • Anzeigen
Alles löschen
neue Beiträge

  • Lambda-Funktion und array_map/_filter gegen foreach

    So, das habe ich jetzt. Die Gründe dazu sind erstmal wurscht, aber ich hab mal wieder eine lustige Performance-Frage
    PHP-Code:
            $tempFunc create_function('$methodName'
                                        
    'return (substr ($methodName, -6) === "Action");');
            
    $actions  array_filter (get_class_methods($this),$tempFunc);
            
    $tempFunc create_function('$methodName',
                                        
    'return substr ($methodName, 0, -6);');
            
    $actions  array_map ($tempFunc$actions);
            
            foreach (
    $actions as $action) {
                
    // Do something useful
            

    Vorher hatte ich das so, bevor ich es auf obige Variante (zu Gunsten der wie ich finde Übersichtlichkeit) umgeschrieben habe:
    PHP-Code:
    $actions get_class_methods ($this);
    foreach (
    $actions as $action) {
        if (
    substr ($methodName, -6) === "Action") {
            continue;
        }
        
    $action substr ($methodName0, -6);');
        // Do something useful

    Naja, wer sich da nicht reinlesen will: Diese beiden Code-Schnippsel lesen die Methoden-Namen der eigenen Klasse, sortieren alle raus, die nicht auf Action enden und schneiden vom Rest das Action am Ende ab.

    Meine Fragen zielen nun auf zwei Sachen:
    1. Was kann man als perfomanter einstufen? Die erste Variante sollte mit array_map und array_filter kleinere Vorteile in Bezug auf Iteration liefern, aber leider wird dann ja insgesamt sogar 3 mal (einmal immer noch mit foreach) über das Array iteriert. Andererseits ist die foreach-Iteration dadurch kleiner und von "Unrat" befreit.

    2. Inwiefern sind die anonymen Funktionen einzuschätzen? Ich hab die da oben nunmal so gebraucht, weil die beiden Array-Funktionen nunmal einstellige Callbacks fordern. Is das aber so sinnvoll? ^^ Denkbar wäre ja auch ne Konstruktion mit array_walk, der beide Schritte gleichzeitig durchzieht. ^^
    Nicht jeder Fehler ist ein Bug.

  • #2
    Hallo KingCrunch,

    ohne das zu testen kann ich dir keine wirklich ehrliche Antwort geben. Ich würde das an deiner Stelle mal benchmarken und anschließend auswerten.

    Wenn es um Ästhetik geht, ziehe ich Version 2 vor, da diese ergeblich schlanker ist. Man könnte sich fast dazu hinleiten lassen und auf Grund der Kompaktheit auch mehr Schnelligkeit zu attestieren..
    Viele Grüße,
    Dr.E.

    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    1. Think about software design [B]before[/B] you start to write code!
    2. Discuss and review it together with [B]experts[/B]!
    3. Choose [B]good[/B] tools (-> [URL="http://adventure-php-framework.org/Seite/088-Why-APF"]Adventure PHP Framework (APF)[/URL][URL="http://adventure-php-framework.org"][/URL])!
    4. Write [I][B]clean and reusable[/B][/I] software only!
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    Kommentar


    • #3
      OK, ma auf die schnelle was auf Basis dieser PHP-Benchmarks was zusammen gebastelt.

      Benchmark-Umgebung:
      PHP-Code:
      <?PHP
      //
      // Wir starten die Zeitmessung - das wird durch Instanzieren
      // einer Timer-Klasse getan
      //
      $start microtime (true);
      //
      // require ('testclss1.php');
      require ('testclass2.php');
      $obj = new test();



      //

      // Schleife für die Iterationen

      //

      for ($meine_zaehlvariable=0$meine_zaehlvariable<10000$meine_zaehlvariable++) {
          
      //
          // Damit eventueller Output nicht angezeigt wird, schreiben wir ihn
          // in den Ausgabe-Puffer
          //
          
      ob_start ();

          
      //
          // Hier steht jeweils der zu prüfende Code
          //
          
      $obj->test ();
          
      //
          // Wir deaktivieren das OB und löschen den Puffer (bei jedem Durchlauf)
          //
          
      ob_end_clean ();
      }
      //
      // Wir bestimmen die Laufzeit
      //

      var_dump (microtime (true) - $start);
      ?>
      Test-Vorraussetzung:
      PHP-Code:
      <?php
      abstract class testPre {
          public function 
      aAction () {}
          public function 
      bAction () {}
          public function 
      cAction () {}
          public function 
      dAction () {}
          public function 
      eAction () {}
          public function 
      fAction () {}
          public function 
      gAction () {}
          public function 
      hAction () {}
          public function 
      iAction () {}
          public function 
      jAction () {}
          public function 
      aElse (){}
          public function 
      bElse (){}
          public function 
      cElse (){}
          public function 
      dElse (){}
          public function 
      eElse (){}
          public function 
      fElse (){}
          public function 
      gElse (){}
          public function 
      hElse (){}
          public function 
      iElse (){}
          public function 
      jElse (){}
      }
      ?>
      Test 1:
      PHP-Code:
      <?php
      require ('testabstract.php');
      class 
      test extends testPre {
          public function 
      test ()
          {
              
      $tempFunc create_function('$methodName',
              
      'return (substr ($methodName, -6) === "Action");');
              
      $actions  array_filter (get_class_methods($this),$tempFunc);
              
      $tempFunc create_function('$methodName',
              
      'return substr ($methodName, 0, -6);');
              
      $actions  array_map ($tempFunc$actions);

              foreach (
      $actions as $action) {
                  
      // Do something useful
              
      }
          }
      }
      ?>
      Test 2:
      PHP-Code:
      <?php
      require ('testabstract.php');
      class 
      test extends testPre {
          public function 
      test ()
          {
              
      $actions get_class_methods ($this);
              foreach (
      $actions as $action) {
                  if (
      substr ($methodName, -6) === "Action") {
                      continue;
                  }
                  
      $action substr ($methodName0, -6);
                  
      // Do something useful
              
      }
          }
      }
      ?>
      Das die zu testenden Methoden leer sind, sollte kein Abbruch darstellen, weil beide Klassen ja den selben Vor-/Nachteil haben. Insofern die (von mir ) gerundeten Ergebnisse:
      - Test 1: Etwa 2 bis 2,2 Sekunden
      - Test 2: Etwa 1,2 bis 1,3 Sekunden
      Die schlankere Variante ist also wirklich schneller. Was ich allerdings noch kritisch betrachte ist, dass die foreach ansonsten leer ist und ich nicht weiß, inwiefern das das Resultat verfälscht ... Und die array_walk-Variante fehlt, aber dazu hab ich auch noch keine mögliche Implementation Vielleicht, ma schaun, aber glaub kaum, dass es das Ergebniss fundamental beeinflusst
      Nicht jeder Fehler ist ein Bug.

      Kommentar


      • #4
        Damit wäre die Vermutung aber bewiesen. Ich benchmarke regelmäßig meinen Code und habe dazu einen benchmarktTimer, den ich in den entsprechenden Code-Teilen singleton einbinde. In der index.php lasse ich mir dann am Ende einen Report ausgeben, der ungefähr so aussieht:

        http://christian.zierpflanzenberatun...arkreport=true

        Sollte er dich interessieren, kannst du dir ja mal die Klasse "benchmarkTimer" im Ordner "/apps/core/benchmark" ansehen unter http://christian.zierpflanzenberatun...eite=Downloads.
        Viele Grüße,
        Dr.E.

        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        1. Think about software design [B]before[/B] you start to write code!
        2. Discuss and review it together with [B]experts[/B]!
        3. Choose [B]good[/B] tools (-> [URL="http://adventure-php-framework.org/Seite/088-Why-APF"]Adventure PHP Framework (APF)[/URL][URL="http://adventure-php-framework.org"][/URL])!
        4. Write [I][B]clean and reusable[/B][/I] software only!
        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

        Kommentar


        • #5
          Die Ausgabe sieht recht interessant aus. Frag mich bloss, ob die ganzen Informationen (Objekt-ID?) wirklich sinnvoll sind. Wie du vielleicht gesehen hast, verwendet die Seite, von der ich mich hab inspirieren lassen, auch ne eigene Klasse. Die konnte ich aber leider net finden, deshalb das schnelle Workaround

          Wollte da mir jetzt auch was zusammen basteln. Möglicherweise lasse ich mich da mal ein bisschen inspirieren Noch steige ich nicht ganz durch, aber sieht vielversprechend aus. Vorallen das mit der kritischen Zeit und die "Stapelung" find ich interessant. Is aber vielleicht nen bisschen viel Ausgabe hardcoded
          Nicht jeder Fehler ist ein Bug.

          Kommentar


          • #6
            Hallo KingCrunch,

            Die Ausgabe sieht recht interessant aus. Frag mich bloss, ob die ganzen Informationen (Objekt-ID?) wirklich sinnvoll sind.
            Das sind sie für mich schon. Hintergrund ist der, dass alle Objekte der Präsentations-Schicht eine interne Objekt-ID haben, mit der man sie im Baum adressieren kann. Da der benchmarkTimer global eingesetzt wird und man ihn mit beliebigen Schlüsseln starten und stoppen kann, brauche ich eine Unterscheidung, welches Objekt gerade z.B. onAfterAppend() ausgeführt hat. Grundsätzlich kannst du aber eigene Schlüssel-Bezeichnungen vergeben um einen Timer zu starten und zu stoppen. Da ich mehrere Timer unterstütze muss der einzelne natürlich unique sein.


            Vorallen das mit der kritischen Zeit und die "Stapelung" find ich interessant. Is aber vielleicht nen bisschen viel Ausgabe hardcoded :Wink
            Die "Stapelung" ist quasi die Hirarchie, in der die einzelnen Timer gestartet werden. Man kann somit einen globalen Prozess in seiner totalen Granularität benchmarken, wenn man das möchte. Daraus ergibt sich dann ein Baum und man sieht genau, wo welche Zeit verbraucht wurde. Die Struktur gibt auch ungefähr die Baum-Struktur der Präsentations-Schicht wieder...
            Die Ausgabe ist einfach nur blödes HTML, nicht unbedingt schön, aber diese Ausgabe wird ja nur dann auch dem User gezeigt, wenn man das auch möchte. Ich brauch mir also keine Gedanken machen, ob der den W3C-Check besteht - was er wahrscheinlich nicht tun wird .
            Viele Grüße,
            Dr.E.

            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
            1. Think about software design [B]before[/B] you start to write code!
            2. Discuss and review it together with [B]experts[/B]!
            3. Choose [B]good[/B] tools (-> [URL="http://adventure-php-framework.org/Seite/088-Why-APF"]Adventure PHP Framework (APF)[/URL][URL="http://adventure-php-framework.org"][/URL])!
            4. Write [I][B]clean and reusable[/B][/I] software only!
            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

            Kommentar

            Lädt...
            X