![]() |
![]() ![]() |
![]() |
![]() ![]()
Post
#1
|
|
Grupa: Zarejestrowani Postów: 7 Pomógł: 0 Dołączył: 16.07.2008 Ostrzeżenie: (0%) ![]() ![]() |
Witam,
to mój pierwszy post, mam nadzieję, że w dobrym dziale, a jak coś z nim nie tak to przepraszam z góry . ![]() A do rzeczy. Piszę skrypt pobierający/aktualizujący dużą ilość danych (kilkanaście tysięcy rekordów), które następnie są wprowadzane do bazy danych MySQL. Skrypt wywoływany przez cron. Tylko tutaj pojawia się problem (nie przy cron, tylko przy przetwarzaniu tych danych). Przy mniejszej ilości (testowej) wszystko jest ok, przy większej - docelowej - oczywiście skrypt wyrzuca błąd o zbyt długim czasie działania. set_time_limit nie wchodzi w grę, bo nie wiem jaka będzie górna granica działania skryptu, a w skrypcie nie ma co optymalizować już. Myślałem żeby jakoś dane wejściowe dzielić na paczki mniejsze, żeby skrypt się "nie zapychał" (przyszło mi do głowy jakieś kombinowanie z wykonywaniem części zapytań i przenoszeniem przez header() z jakims parametrem, żeby dalszą część przetwarzał, ale jakoś nie przekonany do tego byłem, żeby to było najlepsze rozwiązanie), ale nie wiem czy to dobry pomysł, jak w ogole się do tego zabrać, i z taką prośbą o pomoc z tym zwracam się do Was. ![]() Starałem się szukać odpowiedzi na forum i Google, ale z mizernym skutkiem, bo nawet nie wiem jak to dokładnie nazwać... dziękuję z góry za pomoc. |
|
|
![]()
Post
#2
|
|
![]() Grupa: Zarejestrowani Postów: 206 Pomógł: 18 Dołączył: 6.03.2006 Skąd: Szczecin Ostrzeżenie: (0%) ![]() ![]() |
set_time_limit(0); - bez limitu
-------------------- Wrzasq.pl
Tworzenie stron i aplikacji internetowych. Chillout Development - tworzenie stron i aplikacji internetowych. |
|
|
![]()
Post
#3
|
|
Grupa: Zarejestrowani Postów: 7 Pomógł: 0 Dołączył: 16.07.2008 Ostrzeżenie: (0%) ![]() ![]() |
set_time_limit(0); - bez limitu Faktycznie, działa tak. Tylko zastanawiam się czy na hostingu będzie działać, czy może być zmiana tego jakoś zabroniona, że wtedy nie będzie to ustawienie działało? I jeśli tak to jak wtedy można sobie jakoś z tym poradzić? Tak pytam, bo chcę się przy okazji czegoś nauczyć. ![]() |
|
|
![]()
Post
#4
|
|
Grupa: Zarejestrowani Postów: 181 Pomógł: 18 Dołączył: 19.04.2008 Ostrzeżenie: (10%) ![]() ![]() |
pokaz co pobierasz, moze robisz to zle
|
|
|
![]()
Post
#5
|
|
![]() Grupa: Zarejestrowani Postów: 206 Pomógł: 18 Dołączył: 6.03.2006 Skąd: Szczecin Ostrzeżenie: (0%) ![]() ![]() |
jak powiesz dokladnie co i jak pobierasz, to na pewno da sie jakos podzielic na czesci. na hostingu moze niedzialac (chociazby na home.pl).
-------------------- Wrzasq.pl
Tworzenie stron i aplikacji internetowych. Chillout Development - tworzenie stron i aplikacji internetowych. |
|
|
![]()
Post
#6
|
|
Grupa: Zarejestrowani Postów: 7 Pomógł: 0 Dołączył: 16.07.2008 Ostrzeżenie: (0%) ![]() ![]() |
jak powiesz dokladnie co i jak pobierasz, to na pewno da sie jakos podzielic na czesci. na hostingu moze niedzialac (chociazby na home.pl). Właśnie na home sprawdzałem i nie działało. Pobieram dane z Allegro przez WebAPI i SOAP.
To więc tak to wygląda. To jest pobierane po 25 rekordów na jeden przebieg pętli for(i), bo tyle maksymalnie przekazuje WebAPI. |
|
|
![]()
Post
#7
|
|
![]() Grupa: Zarejestrowani Postów: 206 Pomógł: 18 Dołączył: 6.03.2006 Skąd: Szczecin Ostrzeżenie: (0%) ![]() ![]() |
no to pobieraj po jednej porcji i z kazdym wywolaniem skryptu przeskakuj do nastepnej
![]() obejmij inserty transakcja i co kazda porcje wywoluj COMMIT; i zwiekszaj licznik offsetu w bazie. -------------------- Wrzasq.pl
Tworzenie stron i aplikacji internetowych. Chillout Development - tworzenie stron i aplikacji internetowych. |
|
|
![]()
Post
#8
|
|
Grupa: Zarejestrowani Postów: 7 Pomógł: 0 Dołączył: 16.07.2008 Ostrzeżenie: (0%) ![]() ![]() |
Jeśli dobrze zrozumiałem, to proponujesz żeby na każde wywołanie skryptu przez cron'a wykonywał powiedzmy ileś tam porcji, tak żeby zmieścić się w limicie czasu, wcześniej wrzucam w bazę danych dane do kolejnych wywołań skryptu. Na takiej zasadzie to ma działać, dobrze pojąłem?
![]() Tylko w sumie nie chciałbym wywoływać cron'a co 5 minut, tylko np raz na godzinę lub dwie, i żeby przetwarzał powiedzmy te 10-20 minut w zależności od ilości nowych danych, danych do aktualizacji. Tak się teraz zastanawiałem nad dwiema sprawami. Pierwsza to taka, że jak bym zrobił jak powyżej, czyli cron co 5 minut i przetwarza kolejne partie danych, a maksymalny czas wykonywania skryptu na serwerze powiedzmy to 120s (a póki nie mogę sobie pozwolić na jakiś dedykowany to trzeba korzystać z np. home) to przez kolejne 3 minuty do kolejnego wywołania cron'a serwer nic nie robi, a przez ten czas mogłby kolejna partie danych przetworzyć. Druga sprawa to taka, że jeśli będzie ustalony cron co 5 minut to z jednej strony mogłoby być tak, iż przykładowo ustalam wywołanie na 0:00, 0:05, 0:10, 0:15 i powiedzmy wystarcza te 4 wywołania na przetworzenie wszystkiego, ale jak więcej będę miał już danych to nie starczą i dopiero przy kolejnych wywołaniach by dokończyło, co by troche przesunęło dostarczanie danych. Z drugiej strony jeśli bym ustalił cron co 5 min przez 24 h to po przetworzeniu od razu by zaczynało od nowa przetwarzać co troszkę dla mnie jest bez sensu. Wolałbym, żeby wywołanie było raz na godzinę i przetwarzało "od początku do końca" całość materiałów (ale oczywiście dzieląc na mniejsze partie żeby mieścić się w limicie). Jeśli bym poprzez header() wywoływał kolejne przebiegi dla danych to wszystkie razem muszą zmieścić się w czasie czy poszczególne z osobna? Poczytałem o tych transakcjach jak napisałeś, bo nie znałem tego jeszcze i powiem, że chyba zrozumiałem idee tego i nawet całkiem przydatne mogłoby być. ![]() Troszkę się rozpisałem, ale pisząc jakieś takie przemyślenia na ten temat mnie wzięły. Mam nadzieję, że dość zrozumiale napisałem. ![]() Ten post edytował wasilek 17.07.2008, 12:38:16 |
|
|
![]()
Post
#9
|
|
![]() Grupa: Zarejestrowani Postów: 206 Pomógł: 18 Dołączył: 6.03.2006 Skąd: Szczecin Ostrzeżenie: (0%) ![]() ![]() |
Location nie zadziala na cron'a, bo dziala przez CLI. mozesz sie conajwyzej pobawic, w generowanie zapytan HTTP do tego pliku. ale jesli twoj skrypt przekroczy czas wykonywania to nie wygeneruje zadnego zapytania
![]() -------------------- Wrzasq.pl
Tworzenie stron i aplikacji internetowych. Chillout Development - tworzenie stron i aplikacji internetowych. |
|
|
![]()
Post
#10
|
|
![]() Grupa: Zarejestrowani Postów: 1 657 Pomógł: 125 Dołączył: 29.04.2006 Ostrzeżenie: (0%) ![]() ![]() |
Lepiej podzielić to na kilka wykonań, bo jak czasochłonny skrypt, to prawdopodobnie też pamiecio- i procesorożerny. A na hostingach są limity na wykorzystanie RAMu i procka.
-------------------- |
|
|
![]()
Post
#11
|
|
Grupa: Zarejestrowani Postów: 7 Pomógł: 0 Dołączył: 16.07.2008 Ostrzeżenie: (0%) ![]() ![]() |
Hmm, dziękuje Panowie.
![]() Myślałem, że może są jakieś inne sposoby na ugryzienie tego. ![]() To się zastanowię jeszcze, jak to rozwiązać. A tak się jeszcze spytam, przykładowo jeśli miałbym serwer dedykowany i jak dam set_time_limit(0), i po prostu wykonywanie skryptu, to to byłoby najlepsze rozwiązanie, najwydajniejsze, najoczywistsze czy lepiej też dzielić na partie? |
|
|
![]()
Post
#12
|
|
Grupa: Zarejestrowani Postów: 258 Pomógł: 17 Dołączył: 22.05.2007 Ostrzeżenie: (0%) ![]() ![]() |
nie wiem co udostepnia home, ale jesli tylko aktualizujesz baze to moze lepiej napisac cos w perlu lub pythonie?
![]() nie powinno byc wtedy problemow z odpaleniem -------------------- |
|
|
![]()
Post
#13
|
|
![]() Grupa: Zarejestrowani Postów: 1 657 Pomógł: 125 Dołączył: 29.04.2006 Ostrzeżenie: (0%) ![]() ![]() |
A tak się jeszcze spytam, przykładowo jeśli miałbym serwer dedykowany i jak dam set_time_limit(0), i po prostu wykonywanie skryptu, to to byłoby najlepsze rozwiązanie, najwydajniejsze, najoczywistsze czy lepiej też dzielić na partie? Najlepsze rozwiązanie, chyba, że to jest skrypt, który czym dłużej się wykonuje, tym więcej potrzebuje RAMu. -------------------- |
|
|
![]()
Post
#14
|
|
Grupa: Zarejestrowani Postów: 7 Pomógł: 0 Dołączył: 16.07.2008 Ostrzeżenie: (0%) ![]() ![]() |
nie wiem co udostepnia home, ale jesli tylko aktualizujesz baze to moze lepiej napisac cos w perlu lub pythonie? ![]() nie powinno byc wtedy problemow z odpaleniem home udostepnia perl'a, wiec może to faktycznie dobry pomysł. radex_p - myślę, że to nie wyjdzie na taki skrypt, jak analizuję to myślę, że nie będzie zwiększał zapotrzebowania na RAM. |
|
|
![]()
Post
#15
|
|
Grupa: Zarejestrowani Postów: 6 Pomógł: 0 Dołączył: 17.02.2008 Ostrzeżenie: (0%) ![]() ![]() |
Na ograniczenia czasowe na home.pl mam taki sposób. Załóżmy, że limit to 60 sek. Zapisuję microtime() na początku skryptu, po wykonaniu zapytania sprawdzam czy minęło 50 sek, jeśli tak to skrypt kończy wykonywanie, jednocześnie wywołując się sam ponownie:
A) dla skryptów, które wywołuję ręcznie wystarczy header() albo window.location='' z poziomu javascript (użycie javascript ma taką zaletę, że jeżeli sprawdzanie microtime() zawiedzie i skrypt da fatal error, to javascriptowy setTimeout() i tak zrobi redirect po x sekundach, no i można wyświetlać logi informujące o postępie wykonywania - header już wtedy wywołać nie można i na redirect zostaje tylko javascript). B) dla skryptów cron można uzyskać ten sam efekt używając np. CURL z opcją na pobranie pierwszych x bajtów. W przypadku cron'a wypadałoby też dać jakieś ograniczenie w pętli wywołań, żeby nie było sytuacji, że minęło 20 min i nowy skrypt cron zostanie wywołany, a w międzyczasie ciągle stary cron dalej leci. Ten post edytował sarat20 18.07.2008, 03:16:52 |
|
|
![]()
Post
#16
|
|
![]() Grupa: Przyjaciele php.pl Postów: 5 724 Pomógł: 259 Dołączył: 13.04.2004 Skąd: N/A Ostrzeżenie: (0%) ![]() ![]() |
Cytat no to pobieraj po jednej porcji i z kazdym wywolaniem skryptu przeskakuj do nastepnej , przeciez sam masz juz dane podzielone, po prostu nie rob tego w petli, a trzymaj gdzies (na przyklad w bazie danych) offset ostatniego przebiegu i po przejsciu do konca zeruj go. na home.pl mozna tworzyc pliki do cron'a z odstepem 5 minut, sadze ze wystarczy. zreszta powinno sie dac rade wiecej niez jedna porcja jednoczesnie zmiescic. Tez bym cos podobnego polecil 1. zaczynasz, pierwsze uruchomienie skryptu
i masz w tabela_allegrowa_do_update ID userow ktorych dane chcesz pobrac 2. pobierasz kilka IDkow i robisz SOAPa do allegro, zapisujesz dane czy co tam z nimi robisz, i usuwasz! to ID usera, bo juz go przetworzyles i commit na tranzakcje 3. powtarzasz to dla pozostalych ID az ci sie skoncza [w bazie], jak skoncza ci sie te pobrane to pobierasz kolejna porcje 4. jak ci sie skonczy czas wykonania skryptu, to opalasz go kolejny raz, bierzesz kolejne IDki i przetwarzasz jak wyzej, wiesz ktore rekordy przetworzyles a ktore nie. proste? Co do zuzycia pamiecie, memory_get_peak_usage() na koniec skryptu i zobacz jak wyniki sie zmieniaja w zaleznosci od ilosci przetwarzanych userow [czyli wlasciwie na koniec petli morzesz to wrzucic]. -------------------- Nie lubię jednorożców.
|
|
|
![]()
Post
#17
|
|
Grupa: Zarejestrowani Postów: 7 Pomógł: 0 Dołączył: 16.07.2008 Ostrzeżenie: (0%) ![]() ![]() |
To więc tak, zrobiłem małe testy czasu wykonania skryptu i pamięci do liczby aukcji.
308 aukcji - 14,43s - z 2 460 816B do 2 600 272B 825 aukcji - 34,96s - z 2 460 816B do 2 600 496B 1417 aukcji - 61s - z 2 460 816B do 2 600 608B 1894 aukcji - 85,33s - z 2 460 816B do 2 600 808B 4444 aukcji - 194,06s - z 2 461 112B do 2 603 104B Pierwsze 4 pomiary dla 4 różnych pojedynczych użytkowników, ostatni pomiar dla wszystkich razem. Ja wnioskuję (jeśli błędnie to mnie poprawcie), że różnica w pamięci nie jest wielka, więc mam nadzieję, że zasobów nie przekroczę, nawet przy tych 10 000 aukcjach do pobrania. Z pomysłem dr_bonzo to tabela musiałaby chyba zawierać jeszcze dane powiedzmy liczby offsetów i zmniejszać je do zera przy przetworzeniu, a gdy równa zero usunąć użytkownika z tablicy 'do zrobienia'. Bo jak widać, pojedynczy użytkownik co ma 1800 aukcji przetwarzany jest ponad limit powiedzmy 60 sekundowy, więc chyba tak trzeba by to załatwić. A jak miałby wyglądać ten pomysl z wykorzystaniem CURL'a? Chodzi mi o samą ideę. A z zabezpieczeniem przed wywołaniem przez cron kolejnego skryptu to myślę, że po prostu sprawdzenie czy tabela 'do zrobienia' jest pusta, jeśli tak to pobiera dane, a jak nie to przerywa wykonanie. Dobrze myślę? |
|
|
![]()
Post
#18
|
|
Grupa: Zarejestrowani Postów: 6 Pomógł: 0 Dołączył: 17.02.2008 Ostrzeżenie: (0%) ![]() ![]() |
A jak miałby wyglądać ten pomysl z wykorzystaniem CURL'a? Chodzi mi o samą ideę. Za pomocą CURL możesz wykonywać żądania HTTP, czyli np pobrać plik http://test.home.pl/moj-cron.php php.net/curl Z opcją CURLOPT_RANGE (http://pl2.php.net/curl_setopt) - żeby pobrać tylko pierwsze bajty, a nie czekać aż cały skrypt się wykona. Nie pamiętam czy ten range zawiera nagłówki, jeśli nie to w skrypcie należałoby zrobić echo paru bajtów tekstu i flush() żeby natychmiast to wyświetlić. Dla pewności odpal też ini_set('zlib.output_compression', 0). Ten post edytował sarat20 19.07.2008, 15:20:06 |
|
|
![]() ![]() |
![]() |
Wersja Lo-Fi | Aktualny czas: 14.08.2025 - 02:19 |