wieloprocesorowość vs wielowątkowość vs asyncio w Pythonie 3

112

Okazało się, że w Pythonie 3.4 istnieje kilka różnych bibliotek dla wieloprocesorowe / gwintowania: wieloprocesorowe vs gwintowania vs asyncio .

Ale nie wiem, którego użyć, czy jest to „zalecane”. Czy robią to samo, czy różnią się? Jeśli tak, który z nich jest używany do czego? Chcę napisać program korzystający z wielu rdzeni w moim komputerze. Ale nie wiem, której biblioteki powinienem się nauczyć.

user3654650
źródło
1
Może jestem zbyt głupi na AsyncIO pomaga
Martin Thoma

Odpowiedzi:

84

Są przeznaczone do (nieco) innych celów i / lub wymagań. CPython (typowa, główna implementacja Pythona) nadal ma globalną blokadę interpretera, więc aplikacja wielowątkowa (obecnie standardowy sposób implementacji przetwarzania równoległego) jest nieoptymalna. Dlatego multiprocessing może być preferowany threading. Jednak nie każdy problem można skutecznie podzielić na [prawie niezależne] części, więc może zaistnieć potrzeba intensywnej komunikacji międzyprocesowej. Dlatego multiprocessingmoże nie być preferowany threadingw ogóle.

asyncio(ta technika jest dostępna nie tylko w Pythonie, inne języki i / lub frameworki również ją mają, np. Boost.ASIO ) to metoda na efektywną obsługę wielu operacji I / O z wielu jednoczesnych źródeł bez potrzeby równoległego wykonywania kodu . Jest to więc tylko rozwiązanie (rzeczywiście dobre!) Do konkretnego zadania, a nie ogólnie do przetwarzania równoległego.

user3159253
źródło
7
Zauważając, że chociaż wszystkie trzy mogą nie osiągnąć równoległości, wszystkie są w stanie wykonywać współbieżne (nieblokujące) zadania.
sargas
72

[Szybka odpowiedź]

TL; DR

Dokonanie właściwego wyboru:

Omówiliśmy najpopularniejsze formy współbieżności. Pozostaje jednak pytanie - kiedy wybrać który? To naprawdę zależy od przypadków użycia. Z mojego doświadczenia (i czytania) wynika, że ​​kieruję się tym pseudo kodem:

if io_bound:
    if io_very_slow:
        print("Use Asyncio")
    else:
        print("Use Threads")
else:
    print("Multi Processing")
  • Powiązane z procesorem => przetwarzanie wieloprocesowe
  • Ograniczone we / wy, szybkie we / wy, ograniczona liczba połączeń => wielowątkowość
  • Powiązane we / wy, wolne we / wy, wiele połączeń => Asyncio

Odniesienie


[ UWAGA ]:

  • Jeśli masz długą metodę wywołania (tj. Metodę zawierającą czas uśpienia lub leniwe I / O), najlepszym wyborem jest podejście asyncio , Twisted lub Tornado (metody coroutine), które działają z pojedynczym wątkiem jako współbieżnością.
  • asyncio działa na Pythonie 3.4 i nowszych.
  • Tornado i Twisted są gotowe od wersji Python 2.7
  • uvloop jest ultra szybki asynciopętli zdarzenia ( uvloop sprawia asyncio2-4x szybciej).

[UPDATE (2019)]:

  • Japranto ( GitHub ) to bardzo szybki potokowy serwer HTTP oparty na uvloop .
Benyamin Jafari
źródło
Więc jeśli mam listę adresów URL do zażądania, lepiej użyć Asyncio ?
mingchau
1
@mingchau, tak, ale pamiętaj, że możesz użyć od asynciokiedy korzystasz z funkcji oczekujących, requestbiblioteka nie jest metodą oczekiwaną, zamiast tego możesz użyć aiohttpbiblioteki lub żądania asynchronicznego itp.
Benyamin Jafari
proszę rozszerzyć na slowIO i fastIO, aby przejść na wielowątkowość lub asyncio>?
qrtLs
1
Czy możesz doradzić, czym dokładnie jest io_very_slow
zmienna
1
@variable I / O bound oznacza, że ​​program spędza większość czasu na rozmowie z wolnym urządzeniem, takim jak połączenie sieciowe, dysk twardy, drukarka lub pętla zdarzeń z czasem uśpienia. Tak więc w trybie blokowania możesz wybrać między wątkami lub asyncio, a jeśli twoja sekcja ograniczająca jest bardzo powolna, lepszym wyborem jest współpraca wielozadaniowa (asyncio) (tj. Unikanie głodu zasobów, blokad i warunków wyścigu)
Benyamin Jafari
8

Oto podstawowa idea:

Czy to IO -BOUND? ---------> UŻYWAJasyncio

CZY IT PROCESOR JEST CIĘŻKI? -----> UŻYWAJmultiprocessing

JESZCZE? ----------------------> UŻYWAJthreading

Więc zasadniczo trzymaj się wątków, chyba że masz problemy z IO / CPU.

Farsheed
źródło
4

W przypadku przetwarzania wieloprocesowego do dystrybucji obliczeń wykorzystuje się wiele procesorów. Ponieważ każdy z procesorów działa równolegle, możesz skutecznie wykonywać wiele zadań jednocześnie. Chciałbyś użyć przetwarzania wieloprocesowego do zadań związanych z procesorem . Przykładem może być próba obliczenia sumy wszystkich elementów ogromnej listy. Jeśli twoja maszyna ma 8 rdzeni, możesz "pociąć" listę na 8 mniejszych list i obliczyć sumę każdej z tych list oddzielnie na oddzielnym rdzeniu, a następnie po prostu zsumować te liczby. W ten sposób uzyskasz ~ 8x przyspieszenie.

W wielu) ( gwintnie potrzebujesz wielu procesorów. Wyobraź sobie program, który wysyła do sieci wiele żądań HTTP. Jeśli użyłeś programu jednowątkowego, zatrzymałby on wykonywanie (blok) przy każdym żądaniu, czekał na odpowiedź, a następnie kontynuował po otrzymaniu odpowiedzi. Problem polega na tym, że twój procesor tak naprawdę nie działa, czekając, aż jakiś zewnętrzny serwer wykona zadanie; w międzyczasie mógł wykonać pożyteczną pracę! Rozwiązaniem jest użycie wątków - możesz utworzyć wiele z nich, z których każdy będzie odpowiadał za żądanie treści z sieci. Zaletą wątków jest to, że nawet jeśli działają one na jednym procesorze, procesor od czasu do czasu „zawiesza” wykonanie jednego wątku i przeskakuje do wykonania drugiego (nazywa się to przełączaniem kontekstu i dzieje się to stale niedeterministycznie odstępach czasu). - użyj gwintowania.

asyncio to w zasadzie wątkowanie, w którym to nie procesor, ale ty, jako programista (a właściwie twoja aplikacja), decydujesz, gdzie i kiedy ma nastąpić przełączenie kontekstu . W Pythonie używasz awaitsłowa kluczowego, aby zawiesić wykonanie twojego programu (zdefiniowanego za pomocą asyncsłowa kluczowego).

Tomasz Bartkowiak
źródło
Jeśli mam wiele wątków, a następnie szybciej otrzymuję odpowiedzi - a po uzyskaniu odpowiedzi moja praca jest bardziej związana z procesorem - czy mój proces będzie korzystał z wielu rdzeni? To znaczy, czy zamroziłoby wątki zamiast używać wielu rdzeni?
aspirujący 1
Nie jestem pewien, czy zrozumiałem pytanie. Czy chodzi o to, czy należy używać wielu rdzeni, gdy odpowiedzi stają się szybsze? Jeśli tak jest - zależy to od szybkości odpowiedzi i czasu spędzonego na oczekiwaniu na nie w porównaniu z korzystaniem z procesora. Jeśli spędzasz większość czasu na wykonywaniu zadań intensywnie wykorzystujących procesor, korzystne byłoby rozłożenie na wiele rdzeni (jeśli to możliwe). A jeśli pytanie, czy system spontanicznie przełączy się na przetwarzanie równoległe po „zrealizowaniu” swojego zadania, jest związane z procesorem - nie sądzę - zwykle trzeba mu to wyraźnie powiedzieć.
Tomasz Bartkowiak
Myślałem o aplikacji chatbotowej, w której wiadomości użytkowników są wysyłane na serwer, a odpowiedzi są odsyłane przez serwer za pomocą żądania POST? Czy uważasz, że jest to zadanie bardziej obciążające procesor, ponieważ odpowiedź wysłana i odebrana może być json, ale miałem wątpliwości - co by się stało, gdyby użytkownik poświęcił czas na wpisanie swojej odpowiedzi, czy to przykład powolnego wejścia / wyjścia? (użytkownik wysyła odpowiedź późno)
aspirujący 1