2010-01-20 18 views
7

Który wzór istnieje w celu realizacji niektórych procesów PHP i zebrania wyników w jednym procesie PHP?Wzorce dla wielu procesów PHP?

Tło:
mam wiele dużych drzew (> 10000 wpisów) w PHP i trzeba uruchomić kontroli rekurencyjnych na nim. Chcę zmniejszyć czas wykonania.

+4

... napisać rozszerzenie C? – jldupont

Odpowiedz

7

Jeśli Twoim celem jest minimalny czas - rozwiązanie jest łatwe do opisania, ale nie jest łatwe do wdrożenia.

Musisz znaleźć wzór, aby podzielić dzieło (Nie podasz w tej kwestii zbyt wiele informacji).

Następnie należy użyć jednego głównego procesu, który wykonują dzieci, aby wykonać pracę. Z reguły całkowita liczba używanych procesów powinna wynosić od n i 2n, gdzie n to liczba rdzeni maszyny.

Założenie, że dane będą przechowywane w plikach, można rozważyć użycie nieblokujących IO w celu zmaksymalizowania przepustowości. Niewykonanie tej czynności sprawi, że większość czasu spędzonego na przetwarzaniu danych będzie czekała na dysku. PHP ma stream_select(), które mogą ci pomóc. Zauważ, że używanie go nie jest trywialne.

Jeśli zdecydujesz się nie używać select - może pomóc zwiększenie liczby procesów.


W odniesieniu do pcntl funkcje: Napisałem demona z nimi (właściwego jedną z rozwidlającą, zmiana identyfikatora sesji z systemem użytkownika, etc ...) i jest to jeden z najbardziej niezawodnych kawałku oprogramowanie, które napisałem. Ponieważ spawnuje pracowników do każdego zadania, nawet jeśli wystąpi błąd w jednym z zadań, nie ma wpływu na pozostałe.

+0

Dobre trafienie, informacje o stream_select()! – powtac

+0

Aby zobaczyć stream_select w akcji, sprawdź kod w http://drupal.org/project/httprl. Planuję popchnąć tę bibliotekę do githubu, gdy tylko go poprawię; coś, co można uruchomić poza drupalem. Możesz użyć tego jako przykładu na to, jak skomplikowany może być stream_select. – mikeytown2

10

Ze skryptu php można uruchomić inny skrypt (używając exec), aby wykonać przetwarzanie. Zapisz aktualizacje statusu w pliku tekstowym, które mogą być okresowo odczytywane przez wątek nadrzędny.

Uwaga: aby uniknąć oczekiwania na php skrypt exec „d, aby zakończyć, rura wyjście do pliku:

exec('/path/to/file.php | output.log'); 

Alternatywnie można wybulić skryptu za pomocą funkcji PCNTL. Używa on jednego skryptu php, który po rozwidleniu może wykryć, czy to rodzic, czy dziecko i działają odpowiednio. Istnieją funkcje wysyłania/odbierania sygnałów w celu komunikacji między rodzicem/dzieckiem lub dziennikiem potomnym do pliku i rodzicem odczytanym z tego pliku.

Od strony pcntl_fork ręcznej:

$pid = pcntl_fork(); 
if ($pid == -1) { 
    die('could not fork'); 
} else if ($pid) { 
    // we are the parent 
    pcntl_wait($status); //Protect against Zombie children 
} else { 
    // we are the child 
} 
+0

"Usłyszałem", że pcntl nie jest dobrym rozwiązaniem. Jakieś doświadczenia? – powtac

+1

Niestety, nie ma praktycznie żadnego praktycznego doświadczenia. Przeszukując SO, jestem zaskoczony, jak wielu ludzi kategorycznie twierdzi, że nie ma sposobu na rozwidlenie php –

+2

Napisałem perlowe opakowanie przed użyciem FORK (w Perlu) do wykonania skryptu PHP z doskonałymi wynikami. –

4

To może być dobry moment, aby rozważyć użycie message queue, nawet jeśli uruchomić to wszystko na jednej maszynie.

+0

Problem z kolejką komunikatów polega na tym, że potrzebujemy tej samej globalnej przestrzeni nazw/zakresu dla różnych procesów. – powtac

+1

Nie wiem, do czego potrzebny jest współużytkowany zasięg i przestrzeń nazw, ale kolejka komunikatów połączona z pamięcią wspólną (np. Memcache) może być możliwa. – sfrench

+0

Rozwiązanie que wiadomość pasuje najlepiej do tej dużej skalowanej aplikacji. Dzięki memcache możemy kontrolować bardzo dobrze, co robić kiedy. Ponieważ wszystko jest bardzo OO, nie ma dużego problemu z przestrzenią nazw. Muszę tylko wypełnić przedmioty z memcache. – powtac

1

Korzystanie z Internetu lub interfejsu CLI?

Jeśli korzystasz z sieci, możesz połączyć tę część w Quercus Następnie możesz skorzystać z zalet wielowątkowości JAVA.

Nie wiem, jak wiarygodny jest Quercus. Sugerowałbym również użycie rodzaju kolejki komunikatów i refaktoryzacji kodu, więc nie potrzebuje on zakresu.

Może uda Ci się przebudować kod na wzór Mapa/Zmniejsz. Następnie możesz uruchomić kod PHP w Hadoop. Następnie możesz zgrupować przetwarzanie za pomocą kilku maszyn.

Nie wiem, czy to przydatne, ale natknąłem się na inny projekt o nazwie Gearman. Służy także do łączenia procesów PHP. Sądzę, że możesz połączyć to ze skryptem redukującym, jeśli Hadoop nie jest taki, jak chcesz.

+0

Nie chcę używać implementacji PHP w Javie, wydaje się nieco "nadęty". – powtac

+0

Testowałem Quercus, nie jest tak źle, ale nie jest w 100% zgodny z istniejącym kodem. Prawdopodobnie najszybszym rozwiązaniem jest użycie klastra Hadoop. – rtacconi

+0

Mapa/Obniżenie to bardzo dobra wskazówka !!! – powtac

2

Pytanie wydaje się być trochę zagmatwane.

Chcę zmniejszyć bezwzględny czas wykonania.

Masz na myśli upływ czasu? Z pewnością użycie odpowiedniej struktury danych poprawi przepustowość, ale dla danej struktury danych minimalna kolejność algorytmu jest absolutna i nie ma nic wspólnego z tym, jak zaimplementować algorytm.

Który wzór istnieje, aby zrealizować ...?

Wzorce projektowe są czymś, co jest kod , nie szablon do pisania programów, a także użyteczne narzędzia do projektowania programów nauczania. Aby zacząć od wzoru i sprawić, by kod się zmieścił, jest on sam anty-wzorem.

Nikt nie może odpowiedzieć na to pytanie, nie wiedząc o wiele więcej na temat swoich danych i ich struktury, jednak kluczowym czynnikiem wydajności będzie struktura danych, której używasz do implementacji drzewa. Jeśli czas, który upłynął jest ważny, to spójrz na wykonanie równoległe, ale warto również rozważyć wykonanie operacji w innym narzędziu - bazy danych są zoptymalizowane pod kątem obsługi dużych zbiorów danych, jednak należy pamiętać, że oczywistą metodą opisu drzewa jest relacyjna baza danych jest bardzo nieefektywna, jeśli chodzi o izolowanie pod-drzew i chodzenie po drzewie.

W odpowiedzi na Adama sugerując rozwidlenia Ci odpowiedzieli:

I „słyszał”, który PCNTL isnt dobre rozwiązanie. Jakieś doświadczenia?

Gdzie to usłyszałeś? Z pewnością rozwidlenie ze skryptu wywoływanego przez CGI lub mod_php jest złym pomysłem, ale nic złego w robieniu tego z linii poleceń. Czy masz google do długich procesów PHP (bądź ostrzeżony, że istnieje wiele złych informacji tam). Kod, który napiszesz, będzie różnił się w zależności od systemu operacyjnego - czego nie napisałeś.

Podejrzewam, że można rozwiązać dużą część problemów z wydajnością, określając, które części drzewa należy sprawdzić i tylko sprawdzając te części ORAZ uruchamiając sprawdzenia podczas aktualizacji drzewa lub co najmniej zaznaczając węzły jako 'brudny'.

Można je znaleźć pomocne:

http://mikehillyer.com/articles/managing-hierarchical-data-in-mysql/ http://en.wikipedia.org/wiki/Threaded_binary_tree

C.

3

Można użyć bardziej wydajnej struktury danych, takich jak btree. Użyłem raz w Javie, ale nie w PHP.Możesz wypróbować ten skrypt: http://www.phpclasses.org/browse/file/708.html, jest to implementacja btree.

Jeśli to nie wystarcza, można użyć Hadoop do wdrożenia schematu Map/Reduce, jak powiedział Michael. Nie rozwikłałbym procesu PHP, nie wydaje się, aby pomógł w wykonaniu.

Osobiście chciałbym używać PHP jako klienta i umieścić wszystko w Hadoop. Ten samouczek może pomóc: http://www.lunchpauze.com/2007/10/writing-hadoop-mapreduce-program-in-php.html.

Innym rozwiązaniem może być użycie implementacji Java Btree: http://jdbm.sourceforge.net/. JDBM to obiektowa baza danych wykorzystująca strukturę danych Btree +. Następnie można wyszukać w PHP przez wystawienie danych z usługi internetowej lub dostępu do niego bezpośrednio z Quercus

+0

Hadoop jest dobrą rekomendacją! – powtac

0

Pthreads

Jest to dość nowy (od 2012) rozszerzenie PHP dostępny: pthreads. Można go zainstalować przez PECL.

Prosta implementacja w kodzie PHP: rozszerzenie z klasy Thread. Dodaj metodę run() i wykonaj metodę start().

<?php 
// Example from http://www.phpgangsta.de/richtige-threads-in-php-einfach-erstellen-mit-pthreads 
class AsyncOperation extends Thread 
{ 
    public function __construct($threadId) 
    { 
     $this->threadId = $threadId; 
    } 

    public function run() 
    { 
     printf("T %s: Sleeping 3sec\n", $this->threadId); 
     sleep(3); 
     printf("T %s: Hello World\n", $this->threadId); 
    } 
} 

$start = microtime(true); 
for ($i = 1; $i <= 5; $i++) { 
    $t[$i] = new AsyncOperation($i); 
    $t[$i]->start(); 
} 
echo microtime(true) - $start . "\n"; 
echo "end\n"; 

Wyjścia

>php pthreads.php 
0.041301012039185 
end 
T 1: Sleeping 3sec 
T 2: Sleeping 3sec 
T 3: Sleeping 3sec 
T 4: Sleeping 3sec 
T 5: Sleeping 3sec 
T 1: Hello World 
T 2: Hello World 
T 3: Hello World 
T 4: Hello World 
T 5: Hello World 
Powiązane problemy