Autor Zpráva
Sylar
Profil
Zdravím,
mám script s poměrně složitým výpočtem, jedná se o tři vnořené cykly. Chci jej proto umístit na vlastní virtual managed server. Zajímá mne ale na jaké parametry se mám u VMS zaměřit, jaké parametry jsou důležité, aby byl samotný výpočet co nejrychlejší - počet jader, ram paměť, frekvence procesoru?
DJ Miky
Profil
mám script s poměrně složitým výpočtem, jedná se o tři vnořené cykly

To nedává moc informací. Každopádně pokud je výpočtem myšlen např. matematický výpočet, bude tě zajímat hlavně výpočetní výkon procesoru. Ohledně počtu jader a velikosti paměti si na to musíš odpovědět sám. Dokáže aplikace využít více jader (běží ve více vláknech, procesech)? Paměťovou náročnost si snadno změříš sám. Pokud se do paměti vejde a není potřeba využít swap, paměť navíc ničemu nepomůže (pokud daný výpočet nevyužívá mnoho I/O operací, v tom případě může dodatečnou paměť systém využít pro cache).

Jak se dá změřit výpočetní výkon? Těžko. Záleží na mnoha faktorech, mimo jiné např. na využití fyzického serveru ostatními uživateli. Obvykle jsou výpočetní jádra fyzického serveru sdílená napříč virtuálními servery, tedy ostatní uživatelé svým využíváním ovlivňují tebe a ty zase je. Z toho důvodu měj také na paměti, že většina poskytovatelů virtuálních serverů nebude z celodenního vytěžování virtuálního serveru nadšena. Někteří ti v takovém případě omezí dostupný výkon, někteří to mají dokonce v podmínkách zakázáno.

Proto pro výpočetně náročné úlohy může být výhodnější dedikovaný server, kde máš k dispozici plný výkon po celou dobu.

A ještě poznámka na závěr: Popřemýšlej o možnostech optimalizace daného výpočtu. Někdy se dá poměrně jednoduchými optimalizacemi dosáhnout mnohem vyšší rychlosti. Můžeš zkusit identifikovat problémová místa. Nepočítá se něco opakovaně? Nešel by výpočet napsat efektivněji v jiném programovacím jazyce?
margin
Profil *
Podle mě zbytečné se nad nějkaým výpočtem v nějakém jazyce bavit konkrétně, jde o teoretickou rovinu.

Nechceš být konkrétnější? Třeba se bude jedna to výpočet, který nic zatěžovat nebude a řeší se tu zbytečnosti. 3 vnořené cykly mohou být nenáročné, podle situace.
Sylar
Profil
Jedná se o tento algoritmus. Z testů jsem zjistil, že největší čas berou první tři řádky, přičemž nejvíce první řádek

  // $_POST['data'] = {"403750":10,"392812":10,"525784":10,"456062":10,"601643":10,"258381":10}; // testovací data
  
  foreach($_POST['data'] as $key => $val) {
    $radius = floor(pow($val, 1));
    
    $x = floor($key % $_POST['width']);
    $y = floor($key / $_POST['width']);
    
    for($scanx = $x - $radius; $scanx < $x + $radius; $scanx += 1) {
      if ($scanx < 0 || $scanx > $_POST['width']) continue;
      
      for($scany = $y - $radius; $scany < $y + $radius; $scany += 1) {
        if ($scany < 0 || $scany > $_POST['height']) continue;
          
          $dist = sqrt(pow(($scanx - $x), 2) + pow(($scany - $y), 2));
          if ($dist > $radius) {
            continue;
          } else {
            $v = $val - pow($dist, 1);
            
            $id = $scanx + $scany * $_POST['width'];
            if (isset($value[$id]))
              $value[$id] += $v;
            else
              $value[$id] = $v;
  } } } }
juriad
Profil
Můžeš ušetřit čas na funkci pow; raději použij násobení, mělo by být rychlejší.
Také se můžeš zbavit odmocňování, pro porovnání na řádku 16 ti stačí porovnat s $radius * $radius.
DJ Miky
Profil
Odmocnina (sqrt) je poměrně pomalá operace, proto bude o mnoho rychlejší porovnávat druhé mocniny. Stačí si jednou (na začátku) spočítat druhou mocninu poloměru ($radius) a poté porovnávat druhou mocninu vzdálenosti ($dist bez odmocniny) s onou druhou mocninou poloměru.


if ($scanx < 0 || $scanx > $_POST['width']) continue;

Tato podmínka se dá vložit přímo do definice cyklu o řádek výše, aby ses vyhnul zbytečným cyklům, které hned na začátku zařízneš. Např. místo
$scanx = $x - $radius a dodatečné podmínky $scanx < 0
se dá napsat
$scanx = max($x - $radius, 0)
a tím integruješ podmínku na $scanx < 0. Podobně se dá integrovat i opačná podmínka $scanx > $_POST['width'], jen s funkcí min(). Dále, pokud je cyklů hodně, vyplatí se vytáhnout výpočty z ověřovací podmínky ($x + $radius, případně i s integrovaným omezením na $_POST['width']) před cykly, protože se musí při každé kontrole počítat znovu.


pow($val, 1)
pow($dist, 1)

Toto by asi nemělo nijak výrazně zpomalovat výpočet, ale k čemu je mocnit na první?
Sylar
Profil
juriad, DJ Miky:
Díky za tipy. Všechny jsem upravil v kódu a kód se několika násobně zrychlil. Té odmocnině (sqrt) se ale asi stejně nevyhnu, protože na řádku 19 odečítám $dist a tam ji potřebuji mít odmocněnou - nebo jsem něco překouknul a lze to udělat i jinak? Zkoušel jsem namísto sqrt($dist) použít pow($dist, 0.5), ale rychlejší se mi jeví ta sqrt(). Alespoň jsem ji tedy vložil až do klauzule ELSE, aby se počítala pouze v případech kdy je to skutečně potřeba.
juriad
Profil
Sylar:
Ještě několik tipů:
1) Neprováděj aritmetiku s řetězci; konveruj výrazy na čísla (třeba $_POST['width'] je řetězec; porovnávaní a násobení s ním bude pomalejší než s číslem)
2) Pokud je $val (= $radius) vždy stejný, můžeš si předpočítat matici $v o velikosti 2*$radius krát 2*$radius dopředu a potom ji jen celou vhodně posunutou přičíst k poli $value
3) Můžeš zkusit mít pole $value dvojrozměrné a až na konci výpočtu jej konvertovat na jednorozměrné.
4) Můžeš počítání vzdálenosti na řádku 15 použít pro osm různých vstupů:
(m, n) je střed, (m+x, m+y) je mimo střed; pak všechny následující body mají stejnou vzdálenost od středu:
(m+x, m+y); (m+x, m-y); (m-x; m+y); (m-x; m-y); (m+y, m+x); (m+y, m-x); (m-y, m+x); (m-y, m-x)
Smyčku na řádku 9 ($scanx) můžeš počítat jen pro -$radius do 0; obdobně tu druhou pro -$radius do $scanx; vevnitř spočítáš vzdálenost jen jednou; výpočet $id provedeš osmkrát (pro každou variantu)
5) předvyplnit pole $value nulami; pak bys nepotřeboval podmínku na řádku 22
6) Rovnost pro podmínku nerovnosti na řádku 16 bys mohl hledat pro každý sloupec binárním vyhledáváním před provedením smyčky na řádku 12. Podmínka na řádku 15 by se tedy prováděla jen $radius*log($radius) krát.
7) Můžeš zkoušet prokládat výpočet sloupců tak, aby se po sobě počítaly m-y a m+y (u druhého budeš znát dopředu rozsahy platnosti nerovností)
8) Uložit si do proměnné každý kousek, který počítáš stále znovu: $scany se ti mění pořád, kdybys prohodil smyčky, mohl bys $scany * $_POST['width'] (řádek 21) vypočítat mimo jednu smyčku; navíc by pak výpočet $id spočíval jen v inkrementaci.

Některé z těchto tipů mohou být závislé na konstantách, které jsi nezveřejnil; navíc mohou záviset na interní implementaci PHP (cachování, optimalizace).
V tak nepředvídatelném jazyku jako je PHP těžko předem dokázat, že něco pomůže/uškodí.

Vaše odpověď

Mohlo by se hodit


Prosím používejte diakritiku a interpunkci.

Ochrana proti spamu. Napište prosím číslo dvě-sta čtyřicet-sedm: