2009-08-04 35 views
32

Mam aplikację python, która pobiera kolekcję danych i dla każdego elementu danych w tej kolekcji wykonuje zadanie. Wykonanie zadania zajmuje trochę czasu, ponieważ występuje opóźnienie. Z powodu tego opóźnienia nie chcę, aby każdy element danych wykonywał zadanie później, chcę, aby wszystkie one działały równolegle. Czy powinienem używać wieloprocesowości? lub wątki dla tej operacji?wieloprocesorowość lub wątki w python?

Próbowałem używać wątków, ale miałem pewne problemy, często niektóre zadania nigdy nie byłyby uruchamiane.

+0

Jak duża jest twoja "kolekcja danych". Jeśli jest ogromny, możesz nie chcieć uruchamiać wątków lub procesów dla każdego z nich. –

+0

zwykle 1, 2 lub 3 dane. – Ryan

+0

@ S.Lott - jak ograniczyć liczbę wątków/procesów do liczby znacznie mniejszej niż rozmiar danych? –

Odpowiedz

0

Korzystanie z modelu wątków CPython nie zapewni żadnej poprawy wydajności, ponieważ wątki nie są faktycznie wykonywane równolegle, ze względu na sposób, w jaki odbywa się przetwarzanie śmieci. Wieloprocesowość umożliwiłaby równoległe wykonanie. Oczywiście w tym przypadku musisz mieć wiele rdzeni dostępnych do obsadzenia twoich równoległych zadań.

Dostępnych jest znacznie więcej informacji pod numerem this related question.

+4

To nie jest prawda. Nie zapewni Wam DUŻEJ poprawy wydajności, jak to będzie na przykład w C lub C++, ale wystąpi pewna współbieżność. Zwłaszcza jeśli jesteś związany z I/O, to nici nie pomogą. – Christopher

+0

Nie zdawałem sobie z tego sprawy - dziękuję za informację. Oto zewnętrzny odnośnik: http://mail.python.org/pipermail/python-dev/2008-May/079461.html. W tym benchmarku widać poprawę w zakresie problemów związanych z wejściem/wyjściem, które opisujesz. Warto jednak zauważyć, że problem związany z procesorem faktycznie działał ** wolniej ** z 2 wątkami Python niż z 1! Wygląda na to, że profilowanie Twojej aplikacji jest niezbędne. –

7

Dla małych kolekcji danych po prostu twórz podprocesy z subprocess.Popen.

Każdy podproces może po prostu pobrać fragment danych ze standardowego wejścia lub z argumentów wiersza poleceń, zrób to i po prostu zapisz wynik do pliku wyjściowego.

Po zakończeniu wszystkich podprocesów (lub przekroczeniu limitu czasu) po prostu scalono pliki wyjściowe.

Bardzo prosta.

+3

To naprawdę ciężkie rozwiązanie. Nie tylko musisz przygotować dane do zewnętrznego procesu, masz ogromne obciążenie. – Christopher

+1

@ Christopher. Chodzi o prostotę. Świat Unix używa tej techniki od 40 lat. Działa dobrze, ponieważ jest prosty. Ponadto obciążenie nie jest tak naprawdę "masywne", ponieważ uruchamiasz wiele instancji tego samego obrazu binarnego. Jest to zoptymalizowane przez GNU/Linux. –

+8

@ S.Lott: Tylko dlatego, że był używany przez długi czas, nie znaczy, że jest to dobre rozwiązanie. Nie jest to szczególnie dobre rozwiązanie problemów związanych z obliczeniami. Obciążenie jest "masywne", ponieważ mamy narzut pamięci na wszystkie struktury procesu, jak również na opóźnienie wielu przejść jądra. Moduł przetwarzania wieloprocesorowego Pythona tak naprawdę nie tworzy nowego "procesu" takiego jak podproces. Tworzy nowy kontekst interpretera, który jest znacznie lżejszy niż tworzenie nowego procesu na poziomie systemu operacyjnego. – Christopher

7

Możesz rozważyć zaglądanie do Stackless Python. Jeśli masz kontrolę nad funkcją, która zajmuje dużo czasu, możesz po prostu wrzucić tam kilka stackless.schedule() s (z informacją o zyskach dla następnego uczestnika), lub możesz set Stackless to preemptive multitasking.

W Stackless, nie trzeba wątki, ale tasklets lub greenlets które są zasadniczo bardzo lekkie nitki. Działa wspaniale w tym sensie, że istnieje całkiem niezła struktura z bardzo małą konfiguracją, która pozwala działać wielozadaniowo.

Jednak Stackless utrudnia przenoszenie, ponieważ trzeba wymienić kilka standardowych bibliotek Pythona - Stackless usuwa zależność od stosu C. Jest bardzo przenośny, jeśli następny użytkownik również ma zainstalowany Stackless, ale to rzadko się zdarza.

29

Jeśli naprawdę obliczyć związany z wykorzystaniem multiprocessing module jest prawdopodobnie najlżejszym rozwiązaniem wagi (zarówno pod względem zużycia pamięci i trudności realizacji.)

Jeśli jesteś I/O bound, używając threading module zazwyczaj dają masz dobre wyniki. Upewnij się, że używasz bezpiecznego wątku (takiego jak kolejka) do przekazywania danych do wątków. Albo wręcz im jeden kawałek danych, który jest unikalny dla nich, gdy są odradzane.

PyPy koncentruje się na wydajności. Posiada szereg funkcji, które mogą pomóc w przetwarzaniu obliczeniowym. Mają także obsługę Software Transactional Memory, chociaż nie jest to jeszcze jakość produkcji. Obietnica polega na tym, że można użyć prostszych mechanizmów równoległych lub równoległych niż w przypadku wieloprocesowości (co ma pewne niezręczne wymagania).

to również niezły pomysł. Stackless ma problemy z przenośnością, jak wskazano powyżej. Unladen Swallow był obiecujący, ale jest już nieistniejący.Pyston to kolejna (niedokończona) implementacja Pythona koncentrująca się na prędkości. Podejście różni się od PyPy, które może przynieść lepsze (lub po prostu inne) przyspieszenia.

0

Jeśli możesz łatwo podzielić i podzielić dane, które masz, brzmi to tak, jakbyś zrobił to partycjonowanie zewnętrzne i przekazuje je do kilku procesów w twoim programie. (tj. kilka procesów zamiast wątków)

0

IronPython ma prawdziwą wielowątkowość, w przeciwieństwie do CPython i GIL. Tak więc, w zależności od tego, co robisz, warto na to patrzeć. Ale wygląda na to, że twój przypadek użycia lepiej pasuje do modułu wieloprocesowego.

Dla faceta, który poleca bezzałogowego pytona, nie jestem ekspertem od tego, ale wydaje mi się, że mówi o oprogramowaniu "wielowątkowość", które w rzeczywistości nie jest w ogóle równoległe (nadal działa w jednym wątku fizycznym, więc nie można skalować na wiele rdzeni.) Jest to po prostu alternatywny sposób na asynchroniczną (ale wciąż jednowątkową, nierównoległą) aplikację.

9

Zadania działają jak sekwencja, ale masz iluzję, które działają równolegle. Zadania są dobre, gdy używasz plików lub połączeń I/O i dlatego, że są lekkimi.

Wieloprocesorowość z pulą może być właściwym rozwiązaniem, ponieważ procesy działają równolegle, więc są bardzo dobre w przypadku intensywnego przetwarzania, ponieważ każdy proces jest uruchamiany w jednym procesorze (lub rdzeniu).

wieloprocesowe Instalator może być bardzo proste:

from multiprocessing import Pool 

def worker(input_item): 
    output = do_some_work() 
    return output 

pool = Pool() # it make one process for each CPU (or core) of your PC. Use "Pool(4)" to force to use 4 processes, for example. 
list_of_results = pool.map(worker, input_list) # Launch all automatically 
+0

to znaczy, że wszystkie rdzenie działają na tych samych danych? czy jest możliwe podzielenie input_list i przekazanie każdej porcji do różnych rdzeni? – Moj

0

Możesz zajrzeć do Twisted. Jest przeznaczony do asynchronicznych zadań sieciowych.

Powiązane problemy