Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: czy da sie przyspieszyć copy()?
Forum PHP.pl > Forum > PHP
siutek
Witam,
Przygotowuję małą aplikację generującą miniaturki aukcji allegro (w oparciu o Allegro WebApi).
Założenie jest takie, że co 15 minut program sprawdza czy pojawily się nowe oferty w aukcjach, czy zmienila się cena, itp itd. Przy okazji kopiuje miniaturke zdjecia z serwerow alllegro, wczesniej jednak sprawdzam czy nie mam już tego zdjęcia na swoim serwerze, bo po co kopiowac kilka razy to samo?

No i problem z jakim przyszlo mi się zmierzyc, to problem wydajnośći, czasu wykonywania.
- W najgorszym wypadku, aby wygenerować 6 miniaturek, skrypt potrzebuje prawie 8 sekund.
- W najlepszym, gdy nie musze kopiować żadnych miniaturek z zewnatrz wygenerowanie tych 6 grafik trwa okolo 2,5 sekundy

wyliczylem sobie, że samo kopiowanie miniaturki trwa ok 0,8 sekundy.

Jesli używam tego skryptu sam - problemu nie ma.
Jednak chce to udostepnic wiekszej rzeszy ludzi - komercyjnie.

w momencie gdy z systemu zacznie korzystac juz ponad setka ludzi (co wydaje mi sie liczbą śmiesznie małą) czas wykonywania calego skryptu zbliza sie do magicznej granicy 15 minut!! a przecież Cron ma za zadanie co 15 minut odpalac skrypt by zaktualizowac miniaturki.

poniżej wrzucam kod, może ktoś coś z niego wyczyta...

ktoś ma pomysł jak to poprawić? a może należałoby wykorzystać tu inną technologięquestionmark.gif Czekam na jakieś sugestie...

  1. <?php
  2. //error_reporting(E_ALL);
  3. function getmicrotime(){
  4. list($usec, $sec) = explode(" ",microtime());
  5. return ((float)$usec + (float)$sec);
  6. }
  7. $timeStart = getmicrotime();
  8. require_once('/home/siutek/mojaStrona.pl/config.php');
  9. require_once('/home/siutek/mojaStrona.pl/lib/nusoap.php');
  10. $client = new soapclient('http://webapi.allegro.pl/uploader.php?wsdl', true);
  11. $client->decode_utf8 = false;
  12.  
  13. $panele = getList("panels",array("act"=>1));
  14. if(is_array($panele)){
  15. foreach($panele as $p){
  16.  
  17. $userItems = $client->call("doGetUserItems",array("user-id"=>$p["usrAllId"],"webapi-key"=>$configWebApi["apiKey"],"country-id"=>$configWebApi["country"],"limit"=>100));
  18.  
  19. $user = getRecord("users",$p["usrId"]);
  20. if(!file_exists("/home/siutek/mojaStrona.pl/userFiles/".$user["login"]."/panelImg/")) @mkdir("/home/siutek/mojaStrona.pl/usersFiles/".$user["login"]."/panelImg/",0755);
  21.  
  22. if(is_array($userItems["user-item-list"]) && count($userItems["user-item-list"])>0){
  23. $userItemsArr = Array();
  24. shuffle($userItems["user-item-list"]);
  25. $r=1;
  26. $timeForStart = getmicrotime();
  27. foreach($userItems["user-item-list"] as $uI){
  28.  
  29. $newImgName = substr($uI["it-thumb-url"],(strrpos($uI["it-thumb-url"],"/")+1));
  30. if(!file_exists("/home/siutek/mojaStrona.pl/usersFiles/".$user["login"]."/panelImg/".$newImgName.".jpg")) {
  31. copy($uI["it-thumb-url"],"/home/siutek/mojaStrona.pl/usersFiles/".$user["login"]."/panelImg/".$newImgName.".jpg");
  32. $copyImg = " (skopiowano) ";
  33. } else {
  34. $copyImg = " (nie skopiowano) ";
  35. }
  36.  
  37. if($r<=($p["columns"]*$p["rows"])) {
  38. $hSize=200;
  39. $xSize=180;
  40.  
  41. $img = ImageCreateTrueColor($xSize, $hSize);
  42. $img2 = ImageCreateFromJpeg("/home/siutek/mojaStrona.pl/usersFiles/".$user["login"]."/panelImg/".$newImgName.".jpg");
  43.  
  44. $white = ImageColorAllocate($img, 255, 255, 255);
  45. $grey = imagecolorallocate($img, 230, 230, 230);
  46. $black = imagecolorallocate($img, 0, 0, 0);
  47. $red = imagecolorallocate($img, 255, 0, 0);
  48.  
  49. ImageFill($img, 0, 0, $white);
  50. ImageFilledRectangle($img, 0, 0, 180, 16, $grey);
  51. ImageFilledRectangle($img, 0, 113, 180, 164, $grey);
  52.  
  53. imagecopy($img,$img2,26,17,0,0,128,96);
  54.  
  55.  
  56. $size = 8;
  57. $fontB = "/home/siutek/mojaStrona.pl/font/verdanab.ttf";
  58. $fontR = "/home/siutek/mojaStrona.pl/font/verdana.ttf";
  59.  
  60. if(($uI["it-time-left"]<3600) && $uI["it-time-left"]>60) {
  61.  
  62. $leftTimeVal = floor($uI["it-time-left"]/60)." min";
  63.  
  64. } elseif ($uI["it-time-left"]<60) {
  65.  
  66. $leftTimeVal = "poniżej minuty";
  67.  
  68. } elseif (($uI["it-time-left"]>3600) && ($uI["it-time-left"]<86400)) {
  69.  
  70. $leftTimeVal = floor($uI["it-time-left"]/3600)." godz.";
  71.  
  72. } else {
  73. $leftTimeVal = floor($uI["it-time-left"]/86400);
  74. if ($leftTimeVal==1) $leftTimeVal.=" dzień";
  75. else $leftTimeVal.=" dni";
  76. }
  77.  
  78. $timeLeftBox2 = imagettfbbox($size, 0, $fontB, $leftTimeVal);
  79. $tlbX = $timeLeftBox2[2]-$timeLeftBox2[0];
  80. imagettftext($img, $size, 0, (175-$tlbX), 12, $black, $fontB, $leftTimeVal);
  81.  
  82. $timeLeftBox1 = imagettfbbox($size, 0, $fontR, "do końca ");
  83. $tlbX = 180-($timeLeftBox1[2]-$timeLeftBox1[0])-$tlbX;
  84. imagettftext($img, $size, 0, $tlbX-5, 12, $black, $fontR, "do końca ");
  85.  
  86. if($uI["it-bid-count"]>0){
  87. imagettftext($img, $size, 0, 5, 12, $red, $fontR, "Ofert: ".$uI["it-bid-count"]);
  88. }
  89. if($uI["it-buy-now-price"]==0){
  90. $price = imagettfbbox(10, 0, $fontB, "Cena: ".number_format($uI["it-price"], 2,","," ")."zł");
  91. $priceX = (180-($price[2]-$price[0]))/2;
  92. imagettftext($img, 10, 0, $priceX, 186, $black, $fontB, "Cena: ".number_format($uI["it-price"], 2,","," ")."zł");
  93. } else {
  94. $price = imagettfbbox(10, 0, $fontB, "Kup teraz: ".number_format($uI["it-buy-now-price"], 2,","," ")."zł");
  95. $priceX = (180-($price[2]-$price[0]))/2;
  96. imagettftext($img, 10, 0, $priceX, 186, $black, $fontB, "Kup teraz: ".number_format($uI["it-buy-now-price"], 2,","," ")."zł");
  97. }
  98.  
  99. $itemNameArr = explode(" ",$uI["it-name"]);
  100.  
  101. writeTextImg($itemNameArr,130,1);
  102. if(is_array($itemNameArr)) writeTextImg($itemNameArr,144,2);
  103. if(is_array($itemNameArr)) writeTextImg($itemNameArr,158,2);
  104. imagejpeg($img, "/home/siutek/mojaStrona.pl/usersFiles/".$user["login"]."/panelImg/".$r.".jpg");
  105. imagedestroy($img);
  106.  
  107. $userItemsArr[$r]=$uI["it-id"];
  108.  
  109. if($_SERVER["SERVER_ADDR"]=="127.0.0.1") echo "<a href='./link.php?panel=".base64_encode($p["id"])."&item=".$r."'><img src='./usersFiles/".$user["login"]."/panelImg/".$r.".jpg' style='border:0px;'></a><br>".$uI["it-id"]."<br>";
  110.  
  111. echo "wygenerowano ".$r.".jpg ".$copyImg." po ".(getmicrotime()-$timeForStart)." od rozpoczecia petli\n";
  112. $r++;
  113. unset($leftTimeVal);
  114.  
  115. } else {
  116. break;
  117. }
  118. unset($newImgName);
  119. }
  120. updateData("panels",array("items"=>serialize($userItemsArr),"id"=>$p["id"]));
  121. } else {
  122. for($r=1;$r<=($p["columns"]*$p["rows"]);$r++) {
  123. copy("/home/siutek/mojaStrona.pl/pix/itemPanelEmpty.jpg","/home/siutek/mojaStrona.pl/usersFiles/".$user["login"]."/panelImg/".$r.".jpg");
  124. }
  125. updateData("panels",array("items"=>"","id"=>$p["id"]));
  126. }
  127. }
  128. $timeEnd = getmicrotime();
  129.  
  130. echo "Czas wykonywania: ".($timeEnd-$timeStart);
  131. }
  132. ?>
kiler129
Ma być szybciej? Użyj imagemagic zamiast gd2 to po pierwsze.
Po 2 sprawdź jak z tym kopiowaniem ... może zwyczajnie dysk na serwerze jest powolny (masz shared host czy dedyka?).

Kolejna sprawa - workery na prawdę warto przepisać do jakiegoś kompilowanego języka. Nie chce tutaj wywołać wojny kolejnej ale php nigdy demonem szybkości w takich operacjach nie był - tak prosty kod możesz z powodzeniem przepisać do C++, lub chcoiaż jego "najcięższą" część.
wNogachSpisz
Format JPEG pozwala na przechowanie miniaturki w metadanych.
Oznacza to, że gotowa miniaturka jest ukryta wewnątrz oryginalnego obrazka.
Do "wyciągnięcia" takiej miniaturki służy funkcja exif_thumbnail.
Oczywiście nie każdy JPEG będzie ją miał, to zależy generalnie od tago jakim algorytmem kompresującym grafika była ostatnio dręczona.
Nie wnikałem które programy zostawiają te dane a które usuwają,
nie wiem też jak sprawa wygląda w przypadku allegro, trzeba by poświęcić te 15 minut i sprawdzić.

Nie widzę abyś używał funkcji imagecopyresampled
za to widzę że stosujesz imagecopy i w rezultacie i zamiast ładnej miniaturki dostajesz przewlekłą kwadratoliozę sierpowatą.

Tak czy inaczej..
Optymalizowanie skryptów przetwarzających obrazki to rozległy temat.
Próba wykonania tu dobrej roboty bez wiedzy jak działają algorytmy GD2 przypomina błądzenie w ciemnościach.
Pozostaje metoda prób i błędow, przyda się tez odrobina zdrowego rozsądku..

Moje dobre rady, będące jednocześnie strzałami na ślepo:
- Zmniejsz wielkości oryginalnego obrazka, przypuszczalnie skrypt będzie działał szybciej kiedy przyjdzie mu wygenerować miniaturkę z grafiki o mnieszym rozmiarze..
- Ustal czy ImagesMagic nie radzi sobie lepiej z tworzeniem thumbinali..
- Generuj "na szybko" miniaturke o gorszych parametrach i kolejkuj generowanie miniaturki o parametrach docelowych aby uniknąć chwilowych przeciążeń serwera.


Powodzenia!
siutek
jak narazie korzystam z serwera wirtualnego (DreamHost), ale mysle ze gdy przyjdzie krytyczny moment, bedzie mnie stac na serwer dedykowany.
Jednak nie wiem na ile to pomoze, bo nie o predkosc wykonywania nowej grafiki w chwili obecnej chodzi, a o predkosc kopiowania jej pierwowzoru...

z serwerow allegro kopiuje naprawde małe pliki: 128x96px, wiec nie mam sie co bawic w wyciaganie danych EXIF.
Myslalem tez o ImageMagic, i w sumie bede musial spróbowac, ale mysle ze zyskam stosunkowo nie wiele.
Dlatego po glowie chodzi mi juz wykorzystanie innej technologii, ale nie wiem jakiej... poza tym nie znam innej niz PHP - ale jesli bedzie trzeba to sie naucze tongue.gif
zegarek84
nie analizowałem dokładnie skryptu ale wygląda na to, że najwęższym gardłem są synchroniczne połączenia z netem po zapytania i soap i obrazki...

skoro łączysz się aż tyle razy (z twoich wyliczeń i różnicy wynika, że za każdym razem średnio pobierasz 5-6 minaturek + połączenie jeszcze z samą stroną przez SOAP) wykonujesz około 500 połączeń dla 100 userów na same obrazki i to liniowo - skrypt jest wstrzymywany do czasu pobrania poprzedniego - rozwiązaniem może być połączenie asynchroniczne lub chociaż podczymanie połączenia jeśli serwer allegro to wspiera 'keep-alive'... obrazki pobrać możesz asynchronicznie za pomocą curl_multi lub socketów:
http://wezfurlong.org/blog/2005/may/guru-multiplexing
oczywiście wtedy logikę wykonywania pewnych czynności pasuje przerzucić na zdarzeniówkę...

możesz jeszcze spróbować porozbijać skrypt na osobne wykonywanie procesu w tle dla danego usera - ale wyrzucenie wszystkich 100 na konkurujące procesy nie będzie też najlepszym pomysłem:
http://robert.accettura.com/blog/2006/09/1...ssing-with-php/
To jest wersja lo-fi głównej zawartości. Aby zobaczyć pełną wersję z większą zawartością, obrazkami i formatowaniem proszę kliknij tutaj.
Invision Power Board © 2001-2025 Invision Power Services, Inc.