Python Global Interpreter Lock (Gil) workaround na systemach wielordzeniowych przy użyciu taskset na Linuksie?

Więc właśnie skończyłem oglądać ten wykład na Python Global Interpreter Lock (Gil) http://blip.tv/file/2232410 .

Sednem tego jest to,że Gil jest całkiem dobrym projektem dla Systemów jednordzeniowych (Python zasadniczo pozostawia obsługę/planowanie wątków do systemu operacyjnego). Ale może to poważnie odbić się na systemach wielordzeniowych i kończy się na intensywnych wątkach IO, które są mocno blokowane przez intensywne wątki CPU, kosztem przełączania kontekstu, ctrl-C problem [*] i tak dalej.

Więc ponieważ Gil ogranicza nas do wykonywania programu Pythona na jednym CPU, moja myśl brzmi: dlaczego nie zaakceptować tego i po prostu użyć taskset na Linuksie, aby ustawić powinowactwo programu do określonego rdzenia / procesora w systemie (szczególnie w sytuacji, gdy wiele aplikacji Pythona działa na systemie wielordzeniowym)?

Więc ostatecznie moje pytanie jest takie: czy ktoś próbował używać taskset na Linuksie z aplikacjami Pythona (szczególnie podczas uruchamiania wielu aplikacji na Linuksie, aby można było używać wielu rdzeni z jedną lub dwiema aplikacjami Pythona powiązanymi z konkretnym rdzeniem), a jeśli tak, to jakie były wyniki? czy warto to robić? Czy to pogarsza niektóre obciążenia? Planuję to zrobić i przetestować (w zasadzie sprawdzić, czy program zajmuje więcej lub mniej czasu), ale chciałbym usłyszeć od innych o swoich doświadczeniach.

Dodatek: David Beazley (gość prowadzący rozmowę w linked video) zwrócił uwagę, że niektóre rozszerzenia C / C++ ręcznie zwolnij blokadę GIL i jeśli te rozszerzenia są zoptymalizowane dla wielordzeniowych (np. naukowa lub numeryczna analiza danych / etc.) wtedy zamiast czerpać korzyści z multi-core dla number crunching rozszerzenie byłoby skutecznie kaleką, ponieważ jest ograniczone do jednego rdzenia(co potencjalnie znacznie spowalnia program). Z drugiej strony, jeśli nie używasz rozszerzeń takich jak this

Powodem, dla którego nie korzystam z modułu multiprocessing jest to, że (w tym przypadku) część programu jest silnie związana we/wy z sieci (żądania HTTP), więc posiadanie puli wątków roboczych jest świetnym sposobem na wyciśnięcie wydajności z pudełka, ponieważ wątek odpala żądanie HTTP, a następnie ponieważ czeka na We / Wy, rezygnuje z GIL i inny wątek może to zrobić, więc część programu może łatwo uruchomić 100+ wątków bez szkody dla CPU i pozwolić mi faktycznie korzystać z przepustowości sieci, która jest dostępna. Co do stackless Pythona / etc nie jestem zbyt zainteresowany przepisaniem programu lub zastąpienie mojego stosu Pythona (dostępność również byłaby problemem).

[*] tylko główny wątek może odbierać sygnały, więc jeśli wyślesz ctrl-C interpreter Pythona w zasadzie próbuje uruchomić główny wątek, aby mógł obsłużyć sygnał, ale ponieważ nie kontroluje bezpośrednio, który wątek jest uruchamiany (to pozostaje do systemu operacyjnego), w zasadzie mówi OS, aby przełączał wątki, aż w końcu trafi do głównego wątku (co, jeśli masz pecha, może chwilę potrwać).

Author: Mike Pennington, 2009-06-13

7 answers

Nigdy nie słyszałem, aby ktoś używał taskset do zwiększenia wydajności w Pythonie. Nie oznacza to, że nie może się zdarzyć w Twoim przypadku, ale zdecydowanie opublikuj swoje wyniki, aby inni mogli krytykować metody analizy porównawczej i zapewnić walidację.

Osobiście jednak oddzieliłbym twoje wątki We / Wy od wątków związanych z procesorem za pomocą kolejki komunikatów. W ten sposób twój front end jest teraz całkowicie związany z siecią I / O (niektóre z interfejsem HTTP, niektóre z interfejsem kolejki komunikatów) i idealny dla Twojego sytuacja z gwintowaniem. Wtedy proces CPU intense może albo korzystać z przetwarzania wieloprocesowego, albo po prostu być pojedynczymi procesami czekającymi na nadejście pracy w kolejce komunikatów.

W dłuższej perspektywie warto również rozważyć zastąpienie gwintowanego front-endu We/Wy skręconymi lub czymś w rodzaju eventletów , ponieważ nawet jeśli nie poprawią wydajności, powinny poprawić skalowalność. Twój back-end jest teraz już skalowalny, ponieważ możesz uruchomić kolejkę wiadomości na dowolnej liczbie maszyny + procesory w razie potrzeby.

 5
Author: Van Gale,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-06-13 09:51:55

Innym rozwiązaniem jest: http://docs.python.org/library/multiprocessing.html

Uwaga 1: jest to Nie ograniczenie języka Python, ale implementacja CPython.

Uwaga 2: jeśli chodzi o affinity, Twój system operacyjny nie powinien mieć problemu z zrobieniem tego sam.

 8
Author: ynimous,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-06-13 06:49:25

Ciekawym rozwiązaniem jest eksperyment opisany przez Ryana Kelly ' ego na jego blogu: http://www.rfk.id.au/blog/entry/a-gil-adventure-threading2/

Wyniki wydają się bardzo zadowalające.
 3
Author: Leo Pepe,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-11-20 20:57:53

Znalazłem następującą zasadę wystarczającą na przestrzeni lat: jeśli workery są zależne od jakiegoś współdzielonego stanu, używam jednego procesu wieloprocesorowego na rdzeń (CPU bound), a na rdzeń puli poprawek wątków roboczych (i / o bound). System operacyjny zajmie się assigningiem różnych procesów Pythona do rdzeni.

 1
Author: wr.,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-06-13 10:03:58

The Python GIL is per Python interpreter. Oznacza to, że jedynym sposobem na uniknięcie problemów z nim podczas przetwarzania wieloprocesowego jest po prostu uruchomienie wielu interpreterów (tj. używanie oddzielnych procesów zamiast wątków dla współbieżności), a następnie użycie innego prymitywnego protokołu IPC do komunikacji między procesami (np. sockets). Biorąc to pod uwagę, Gil nie stanowi problemu podczas używania wątków z blokowaniem połączeń We / Wy.

Głównym problemem GIL jak wspomniano wcześniej jest to, że nie można wykonaj 2 różne wątki kodu Pythona w tym samym czasie. Blokowanie wątku na blokującym wywołaniu I / O jest blokowane i dlatego nie wykonuje kodu Pythona. Oznacza to, że nie blokuje GIL. Jeśli masz dwa zadania intensywne dla procesora w oddzielnych wątkach Pythona, to właśnie tam GIL zabija multi-processing w Pythonie (tylko implementacja CPython, jak wspomniano wcześniej). Ponieważ GIL uniemożliwia CPU # 1 wykonywanie wątku Pythona, podczas gdy CPU #0 jest zajęty wykonywaniem innego wątku Pythona.

 1
Author: Merijn,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-06-13 19:21:22

Dopóki GIL nie zostanie usunięty z Pythona, można używać Ko-procedur zamiast wątków. Z dobrego źródła wiem, że strategia ta została wdrożona przez dwa udane start-upy, wykorzystujące greenlets w co najmniej jednym przypadku.

 1
Author: ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-06-17 07:43:33

Jest to dość stare pytanie, ale ponieważ za każdym razem, gdy szukam informacji związanych z Pythonem i wydajności w systemach wielordzeniowych ten post jest zawsze na liście wyników, nie pozwolę, aby to minęło przede mną i nie dzielić się moimi przemyśleniami.

Możesz użyć modułu wieloprocesorowego, który zamiast tworzyć wątki dla każdego zadania, tworzy inny proces kompilatora cpython interpretującego Twój kod. Sprawiłoby to, że Twoja aplikacja skorzystałaby z systemów wielordzeniowych. Jedyny problem, który widzę w tym podejściu jest to, że będziesz miał znaczny narzut, tworząc cały nowy stos procesów w pamięci. ( http://en.wikipedia.org/wiki/Thread_ # How_threads_differ_from_processes )

Python Multiprocessing module: http://docs.python.org/dev/library/multiprocessing.html

"powodem, dla którego nie używam modułu wieloprocesorowego, jest to, że (w tym przypadku) część programu jest silnie związana z siecią I / O (żądania HTTP), więc posiadanie puli wątków roboczych to świetny sposób na wyciśnięcie wydajności z pudełka..."

Co do tego, to chyba też możesz mieć pulę procesów: http://docs.python.org/dev/library/multiprocessing.html#using-a-pool-of-workers

Att, Leo

 0
Author: Leo Pepe,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-01-19 13:33:53