![]() |
![]() |
![]()
Post
#1
|
|
![]() Grupa: Zarejestrowani Postów: 338 Pomógł: 2 Dołączył: 4.03.2006 Skąd: Łódź Ostrzeżenie: (0%) ![]() ![]() |
Dawno mnie tu nie było
![]() Forumowicze, problem z kolejką w PHP. System, który tworzę przetwarza dane co minutę (z CRONa). Niestety uruchomienie pojedynczego procesu np, przetwarzaj.php nie kończy się w 1 minucie, ponieważ przetwarzanie danych może trwać np. 2 mninuty dla pojedynczego rekordu bazy danych, a rekordów jest np. 20. Teoretycznie szeregowe uruchomienie przetwarzania zajmie więc 40 min. Każdy przetwarzaj.pho bierze z bazy zatem 1 rekord i tylko taki mieli. Moje pytanie: w jaki sposób napisać kolejkę, która poprawnie przetworzy takie dane? Wywołać z crona 20x ten sam przetwarzaj.php? Zanim proces zacznie wykonywać swoją pracę, ustawia na rekordzie bazy, że jest on przetwarzany, więc inny proces weźmie kolejne dane. Spotkaliście się z podobnym problemem, macie pomysły? |
|
|
![]() |
![]()
Post
#2
|
|
![]() Grupa: Zarejestrowani Postów: 6 476 Pomógł: 1306 Dołączył: 6.08.2006 Skąd: Kraków Ostrzeżenie: (0%) ![]() ![]() |
Podstawowe pytanie: czy przetworzenie kilku, np. maksymalnie pięciu, elementów na raz działa szybciej od przetwarzania kolejnych elementów po kolei?
|
|
|
![]()
Post
#3
|
|
![]() Grupa: Zarejestrowani Postów: 338 Pomógł: 2 Dołączył: 4.03.2006 Skąd: Łódź Ostrzeżenie: (0%) ![]() ![]() |
Tak, przecież zostaną wykonane równolegle. Wykonają się zatem w ciągu 2 minut, zamiast 40.
|
|
|
![]()
Post
#4
|
|
Grupa: Zarejestrowani Postów: 4 298 Pomógł: 447 Dołączył: 16.11.2006 Ostrzeżenie: (0%) ![]() ![]() |
Tak, przecież zostaną wykonane równolegle. Wykonają się zatem w ciągu 2 minut, zamiast 40. Chciałbyś. Przecież "moc" obliczeń jest identyczna,więc jak zaginasz czasoprzestrzeń? Ten post edytował !*! 23.05.2012, 07:13:39 -------------------- Nie udzielam pomocy poprzez PW i nie mam GG.
Niektóre języki programowania, na przykład C# są znane z niezwykłej przenośności (kompatybilność ze wszystkimi wersjami Visty jest wiele warta). |
|
|
![]()
Post
#5
|
|
![]() Grupa: Zarejestrowani Postów: 142 Pomógł: 24 Dołączył: 30.03.2009 Skąd: Rokitno Szlacheckie Ostrzeżenie: (0%) ![]() ![]() |
Zły tok rozumowania... równoległe uruchomienie spwoduje że wszystkie procesy będą działać wolniej... więc zamiast upragnionych 2 minut będzie to 20 (lub i więcej)...
jak zrobić? napisać skrypt który w pętli odpali te 20 zadań np
Ten post edytował hind 23.05.2012, 07:05:43 |
|
|
![]()
Post
#6
|
|
![]() Grupa: Zarejestrowani Postów: 338 Pomógł: 2 Dołączył: 4.03.2006 Skąd: Łódź Ostrzeżenie: (0%) ![]() ![]() |
No bez przesady. 16 rdzeni przetworzy szybciej 16 równoległych procesów, niż 1 ciągły. Proces nie może wykonać się szeregowo, bo już pierwsze przetwarzanie danych może zająć dużo czasu, a przetwarzanie musi odbywać się co minutę. Pomysł hind wnosi coś do dyskusji.
|
|
|
![]()
Post
#7
|
|
![]() Grupa: Zarejestrowani Postów: 6 476 Pomógł: 1306 Dołączył: 6.08.2006 Skąd: Kraków Ostrzeżenie: (0%) ![]() ![]() |
To może inaczej, co jest powodem tak długiego przetwarzania pojedynczego rekordu? Bo jeżeli są to jakieś ciężkie operacje wykorzystujące procesor albo dysk, wykonanie równoległych przetwarzań wcale nie musi przyspieszyć ich ogólnego czasu wykonywania. Zaś jeżeli jest to spowodowane przykładowo oczekiwaniem na pobranie danych z sieci to już jak najbardziej miałoby to sens.
1. Zamiast odpalać co minutę zadanie w Cronie, utwórz sobie daemona(y) (System_Daemon). 2. Generalnie utworzenie w bazie danych kolumny status (awaiting, processing, processed) będzie niewystarczające. Dwa (lub nawet więcej) procesy mogłyby pobrać ten sam wiersz nim którykolwiek z nich zdąży zmienić jego status z awaiting na processing. Tutaj trzeba by było albo zablokować na chwilę tabelę dla odczytu:
3. Jeżeli masz możliwość nie pisz tego w PHP, tylko w czymś co wspiera współbieżność (ot, chociażby Java) - znacznie uprości Ci to życie. EDIT: Ewentualnie zamiast ręcznego bawienia się w blokowanie tabeli skorzystaj z transakcji, i tak zawsze trzeba, na odpowiednim poziomie izolacji - tutaj potrzebny byłby chyba aż poziom serializable. Ten post edytował Crozin 23.05.2012, 07:38:35 |
|
|
![]()
Post
#8
|
|
![]() Grupa: Zarejestrowani Postów: 338 Pomógł: 2 Dołączył: 4.03.2006 Skąd: Łódź Ostrzeżenie: (0%) ![]() ![]() |
No to jest odpowiedź na wysokim poziomie
![]() Proces nie obciąża procesora. Długo wykonuje się, ponieważ przesyła dane i też niedużo, ale klient odbierający dane przetwarza je i to zajmuje czas. Nawet gdyby 2 procesy dobrały się do tych samych danych nic się nie stanie, klient otrzyma je drugi raz co będzie skutkowało najwyżej ponownym przemieleniem danych. Jeśli chodzi o Javę, to faktycznie mógłbym jej użyć, ale to banalny kod w PHP, jeśli udałoby się tylko wywołać 20 równoległych procesów to myślę, że byłoby OK. Co z forkowaniem? Jak ten Demon w PHP? Ktoś to wdrażał w profesjonalnych zastosowaniach? |
|
|
![]()
Post
#9
|
|
![]() Grupa: Zarejestrowani Postów: 6 476 Pomógł: 1306 Dołączył: 6.08.2006 Skąd: Kraków Ostrzeżenie: (0%) ![]() ![]() |
Cytat Proces nie obciąża procesora. Długo wykonuje się, ponieważ przesyła dane i też niedużo, ale klient odbierający dane przetwarza je i to zajmuje czas. Tak więc tutaj może to mieć rzeczywiście sens. Musisz tylko pamiętać, że jednoczesne podesłanie znaczącej ilości żądań do drugiej strony może ją "zamulić" i w efekcie jeszcze bardziej wydłużyć ogólny czas działania. Prawdopodobnie dobrym pomysłem będzie wysyłanie jakiejś ograniczonej ilości żądań jednocześnie, np. 5 albo 20.Cytat Jeśli chodzi o Javę, to faktycznie mógłbym jej użyć, ale to banalny kod w PHP, jeśli udałoby się tylko wywołać 20 równoległych procesów to myślę, że byłoby OK. Tak na pierwszy rzut oka, wykonanie tego np. w Javie będzie znacznie prostsze niż w PHP. Jeden wątek pobierający rekordy do obrobienia (w ilości np. 100), który będzie je wrzucać na stos oraz 5-10-20 wątków pobierających po jednym elemencie ze stosu i przetwarzających go. W momencie gdy ilość rekordów na stosie się kończy będzie on pobierać sobie następną porcję.Zero problemów z wielokrotnym obrabianiem tego samego rekordu, "prosta" baza danych nie wymagająca żadnego dbania o współbieżność (brak LOCKów), jeden proces w systemie zamiast n+1 (czyli łatwe okiełznanie tego). Całość pewnie w 50 linijkach kodu by się zmieściła, z czego połowa to pewnie by były klamerki. Cytat Co z forkowaniem? Jak ten Demon w PHP? Ktoś to wdrażał w profesjonalnych zastosowaniach? W forkowanie nigdy się w PHP nie bawiłem - ono się po prostu do tego kompletnie nie nadaje. Daemon w PHP? Jak najbardziej, ale pojedynczy.EDIT: Oczywiście strukturą danych przechowującą rekordy do przetworzenia powinna być tytułowa kolejka, nie stos. Ten post edytował Crozin 23.05.2012, 19:43:37 |
|
|
![]()
Post
#10
|
|
Grupa: Zarejestrowani Postów: 1 195 Pomógł: 109 Dołączył: 3.11.2011 Ostrzeżenie: (10%) ![]() ![]() |
Php z natury nie jest wielowątkowe(czyt.threading), pozostaje kolejkowanie, albo "emulacja" wielowątkowości poprzez użycie pamięci wspóldzielonej.
Taka implementacja wielowątkowości w PHP: http://www.php.blogle.info/2011/nietypowe-...atkowosc-w-php/ Ten post edytował Niktoś 23.05.2012, 19:16:07 |
|
|
![]()
Post
#11
|
|
![]() Grupa: Zarejestrowani Postów: 338 Pomógł: 2 Dołączył: 4.03.2006 Skąd: Łódź Ostrzeżenie: (0%) ![]() ![]() |
Zrobione za pomocą forkowania. Aż miło patrzeć jak to działa
![]()
Wynik:
|
|
|
![]()
Post
#12
|
|
![]() Grupa: Zarejestrowani Postów: 6 476 Pomógł: 1306 Dołączył: 6.08.2006 Skąd: Kraków Ostrzeżenie: (0%) ![]() ![]() |
Aż mnie coś wzięło, żeby zobaczyć jak można zrobić to "normalnie" (czyt: bez forkowania procesów, a z użyciem normalnych wątków):
Minusy: - konieczność zrezygnowania z PHP dla tego elementu systemu. Plusy: - będzie działać na każdej platformie, - gwarantuje, że rekordy zostaną przetworzone w odpowiedniej kolejności oraz tylko i wyłącznie jeden raz, - brak niepotrzebnych przerw w działaniu, - kontrola nad ilością przetwarzanych rekordów w danym momencie, - łatwiej to wszystko ogarnąć, wprowadzać zmiany itp. |
|
|
![]()
Post
#13
|
|
Grupa: Zarejestrowani Postów: 23 Pomógł: 0 Dołączył: 5.12.2006 Ostrzeżenie: (0%) ![]() ![]() |
Witajcie,
Pewnie mnie teraz zjedziecie, bo jak śmiem... ![]() Ale zaryzykuję. Uważam, że metody które podaliście, to zabijanie muchy przy użyciu czołgu. Ja swojego czasu miałem podobny problem. Potrzebowałem mechanizmu częstego uruchamiania procesu, który może trwać chwilę, lub pół godziny, i warunek - procesy nie mogły działać równolegle. I rozwiązałem to na zasadznie sprawdzania pliku typu lock. czyli coś w stylu: jeden plik odpalany np. co minutę z crona (np cron.php)
oraz drugi plik zrob_cos.php który wykonywał nasze zadania. To taki ogólny zarys, ale.. proste, banalne i skuteczne ![]() Ten post edytował cezet 30.05.2012, 13:13:31 |
|
|
![]()
Post
#14
|
|
![]() Grupa: Zarejestrowani Postów: 6 476 Pomógł: 1306 Dołączył: 6.08.2006 Skąd: Kraków Ostrzeżenie: (0%) ![]() ![]() |
Cytat [...] procesy nie mogły działać równolegle. A zauważyłeś, że cały wątek tyczy się właśnie równoległego odpalenia wielu procesów/wątków?
|
|
|
![]()
Post
#15
|
|
Grupa: Zarejestrowani Postów: 320 Pomógł: 29 Dołączył: 3.04.2010 Ostrzeżenie: (20%) ![]() ![]() |
Nie zjedziemy, acz wytkniemy błąd.
Ten skrypt to tylko semafor zapobiegający uruchomieniu dwóch instancji tego skryptu. Autor natomiast chciałby równloegle przetwarzać te rekordy, rozłożyć je na kilka wątków (serwer jak autor pisał 16-rdzeniowy), dzięki czemu zadania będą się wykonywały równolegle. |
|
|
![]()
Post
#16
|
|
Grupa: Zarejestrowani Postów: 23 Pomógł: 0 Dołączył: 5.12.2006 Ostrzeżenie: (0%) ![]() ![]() |
Zwracam honor
![]() |
|
|
![]() ![]() |
![]() |
Aktualny czas: 19.08.2025 - 03:31 |