MikoAndras.hu

Mikó András személyes oldalai

Kód-optimalizálás php-ban

Fogyókúra – memóriaoptimalizálás

A memóriaoptimalizálási lépésben a támadott kód a teljes script. Bármelyik sarokban lehet olyan rész, ami működőképes marad egy kicsivel kevesebb memóriahasználattal is.

Most átmegyünk behajtóba, és az eddig kölcsönadott memóriából kérünk vissza. Nem is keveset…

Támadási pontok:

  • nem használt adatok mellékessé tétele
  • kézi vezérlésű “szemétgyűjtés” (garbage collect)
  • adatstruktúra újratervezése

Nem használt adatok

A negyedik variációnál elkezdtük a cache-tömb kulcsait vizsgálni, és ezáltal a tömb érték oldalán lévő adatok már csak a foreach-ben kerülnek elő:

      [...]
        foreach ($variation_cache[$passengers - $rn] as $variation) {
      [...]

Van egy kiterjesztett változata a foreach-nek, amivel a kulcsot is ki tudjuk olvasni lokális változóba. Ezzel a megközelítéssel a tömb érték oldala teljes egészében feleslegessé válik, mivel mindenhol csak a kulcsokon végzünk műveletet. Azt pedig hamar beláthatjuk, hogy az aktuális variáció mint érték letárolásához képest a boolean:true sokkal kevesebb helyet foglal.

Módosítás után:

      [...]
        foreach ($variation_cache[$passengers - $rn] as $variation => $devnull) {
      [...]
            $variation_cache[$passengers][$actual_variation] = true;
      [...]
          $variation_cache[$passengers][$rn] = true;
      [...]

Manuális GC

A kód csak olyan régebbi variációkat használ, amik nem kisebb, mint 4 távolságra vannak az aktuális vendégszámtól:
Q(n) = unique( Q(n-1) + Q(n-2) + Q(n-3) + Q(n-4) )

Éppen ezért minden ennél régebbi variáció-tömb eldobható, mert a későbbiekben nem lesz rá szükség.

  function calc_room_use ($passengers, &$variation_cache) {
    [...]
    unset($variation_cache[$passengers - 4]);
  }

Ezzel a kis aprósággal rávesszük a szemétgyűjtőt, hogy szabadítsa fel a már nem használt memóriaterületet. Az automatikus gyűjtés ugyanis nem működne rá, mivel folyamatosan életben marad a $variation_cache, és ezáltal a nem használt tömbökre mutató címek is.

Adatstruktúra újratervezése

Sok esetben kódmódosítások alkalmával előfordul, hogy korábbi verzióból megörökölt adatstruktúrákkal, elgondolásokkal dolgozunk tovább, holott lenne gyorsabb/kisebb megoldás is. Ilyenkor érdemes meglépni a változtatást, mert adott esetben sokat nyerhetünk vele.
Az aktuális variációt tartalmazó szövegsor, az emberi fogyasztásra alkalmas kialakítás miatt tartalmazott “,”-t az első verzió óta. Ez nagyban megkönnyítette az explode és implode olvashatóságát is (funkcionalitását nem befolyásolta, hogy van-e elválasztó vagy nincs).
Ez jelenleg a következő (30 főre):

          $actual_variation = "1,1,1,1,2,2,3,3,4,4,4,4";

Mivel azonban tudjuk, hogy a szobaméreteket adó számok kivétel nélkül egyjegyűek, így nincs szükség elválasztó karakterre, hogy az algoritmus hiba nélkül tudjon futni. Egy apró módosítással a variáció már csak majdnem fele mennyiséget foglal, számítási szemszögből azonban teljesen egyenértékű:

          $actual_variation = "111122334444";

Az új kódrészletek ezek alapján:

      [...]
            $actual_variation = $rn . $variation;
      [...]
            $actual_variation = $variation . $rn;
      [...]
                $actual_variation = substr_replace($variation, $rn, $pos + 1, 0);
      [...]

A hatodik verzió erőforrásigénye:

Számítási idő v6

Számítási idő v6

Memóriahasználat v6

Memóriahasználat v6

Szöveges értelmezésben:

  • 1 másodpercen belül kiszámítható: 98 fő
  • 30 másodpercen belül kiszámítható: 222 fő
  • 25 fő érkező vendég kiszámítása: 0.006 másodperc
  • 128MB memórialimit elérése: 257 vendég számításánál

Értékelés: ehhez már adnám a nevem

A hatodik verzió hónapokkal később jött létre, mint – az eredeti kiírást már teljesítő, de még mindig gyerekcipős – második verzió. Ezek alapján úgy gondolom az evolúciója még nem ért véget. Amennyiben a v6-ra úgy tekintünk, mint a “code sapiens”-re, minden valószínűsége megvan a “code sapiens superior” létezésének…

Mivel az első verzió kódja is teljes terjedelmében szerepel, úgy érzem helyesnek, ha a v6 is felkerül (ezúttal kommentek nélkül, mivel szinte minden sora bemutatásra került az előző oldalakon):

<?php
  $variation_cache = array(0 => array());
  function calc_room_use ($passengers, &$variation_cache) {
    if ($passengers < 1) {
      return 0;
    }
    for ($rn = 1; $rn <= 4; $rn += 1) {
      if ($passengers >= $rn) {
        if (! isset($variation_cache[$passengers - $rn])) {
          calc_room_use($passengers - $rn, $variation_cache);
        }
        if (! isset($variation_cache[$passengers])) {
          $variation_cache[$passengers] = array();
        }
        $actual_variation = $rn;
        foreach ($variation_cache[$passengers - $rn] as $variation => $devnull) {
          if ($rn == 1) {
            $actual_variation = $rn . $variation;
          } else if ($rn == 4) {
            $actual_variation = $variation . $rn;
          } else {
            for ($lrn = $rn; $lrn > 0; $lrn -= 1) {
              $pos = strrpos($variation, (string)$lrn);
              if ($pos !== false) {
                $actual_variation = substr_replace($variation, $rn, $pos + 1, 0);
                break;
              }
            }
          }
          if (! isset($variation_cache[$passengers][$actual_variation])) {
            $variation_cache[$passengers][$actual_variation] = true;
          }
        }
        if ($passengers == $rn && ! isset($variation_cache[$passengers][$rn])) {
          $variation_cache[$passengers][$rn] = true;
        }
      }
    }
    unset($variation_cache[$passengers - 4]);
  }
  calc_room_use($passengers, $variation_cache);
  echo count($variation_cache[$passengers]);
?>

A következő oldalon pedig a menedzserlelkületűek elégíthetik ki grafikongyűjtemény és táblázat iránti igényeiket.

Pages: 1 2 3 4 5 6 7

, , ,

Comments are currently closed.