Współdzielenie stanu między rozwidlonymi procesami roboczymi w środowisku o wysokiej wydajności
To jest kontynuacja mojegopoprzednie pytanie. Jak zasugerował Tim Peters, używając aManager
niekoniecznie musi być najlepszym podejściem. Niestety mam za dużo kodu rusztowania, aby opublikowaćSSCCE. Zamiast tego postaram się przedstawić szczegółowe wyjaśnienie mojego problemu. Zapraszamy do przeglądania całej bazy kodówGithub, ale teraz jest trochę bałaganu.
Robię badania w Natural Language Processing i chciałbym zrobić (coś w rodzaju) słownikowe wygładzanie klasyfikacji dokumentów. Pomysł wyszkolenia klasyfikatora, aby skojarzył słowa i frazy z poprawną odpowiedzią. Na przykład dokumenty zawierające słowosocialist
prawdopodobnie będą dotyczyć polityki i tych, które zawierają tę frazęlava temperature
prawdopodobnie dotyczy geologii. System jest szkolony, patrząc na amały numer przykładów z etykietami. Ponieważ język jest tak zróżnicowany, klasyfikator nigdy „nie wie” o wszystkich możliwych frazach, które może napotkać w produkcji.
W tym miejscu znajduje się słownik. Załóżmy, że taktani i łatwy sposób uzyskiwania synonimów prawie każdej frazy (powołam się, ponieważ jest to słaby smak). Kiedy biedny klasyfikator napotyka frazę, o której nie wie, moglibyśmy go znaleźć we wspomnianym słowniku i powiedzieć klasyfikatorowi „Patrz, nie wiesz o tymcommunism
, ale to trochę taksocialist
i wiesz o tym! ”. Jeśli słownik jest rozsądny, klasyfikator będzie ogólnie lepiej działać.
data = Load training and testing documents (300MB on disk)
dictionary = Load dictionary (200MB - 2GB on disk) and place into a `dict` for fast look-ups
Repeat 25 times:
do_work(data, dictionary)
def do_work(data, dictionary)
X = Select a random sample of data
Train a classifier on X
Y = Select a random sample of data
Using dictionary, classify all documents in Y
Write results to disk
ProblemPowyższa pętla jest idealnym kandydatem do równoległości. Używam Pythona 2.7multiprocessing.Pool
(przezjoblib.Parallel
, ponieważ jest to łatwe i zapewnia bardzo przydatne śledzenie, jeśli sprawy idą na południe). Wszystkie procesy robocze potrzebują dostępu tylko do odczytu do słownika i kolekcji dokumentów. Nie ma potrzeby, aby pracownicy komunikowali się ze sobą lub z procesem macierzystym - wszystko, co robią, to spawn, magia, napisanie pliku i śmierć.
Słownik musi obsługiwać szybki dostęp losowy. Nie wiem, co dokumentuje próbkęY
będzie zawierać, więc nie mogę łatwo przyciąć słownika i przekazać tylko jego część potrzebną każdemu pracownikowi. Słownik będzie pytany bardzo często - typowe liczby trafień na bieg wynoszą miliony. Obecnie mój kod jest związany z pamięcią, ponieważ (jak sądzę) dla każdego procesu roboczego tworzone są kopie kolekcji dokumentów i słownika. Po przeanalizowaniudata
idictionary
zazwyczaj zużywają kilka GB pamięci RAM. Próbowałem użyćmultiprocessing.managers.BaseManager
aby uniknąć kopiowania dużych obiektów, ale spowolniło to pracowników.
Jakie są inne możliwości przyspieszenia? Do rzeczy, o których myślałem, należą:
MongoDB / CouchDB / memcached powinny dobrze obsługiwać współbieżny dostęp, ale martwię się o przepustowość. zeromq został także zasugerowany w komentarzu do mojego poprzedniego pytania, nie miałam okazji zajrzeć do tego.w pamięcisqlite
bazy danych i połączenia z bazami danych nie mogą być współużytkowane przez procesy, więc każdy pracownik będzie potrzebował własnego połączenia z bazą danych na dysku. Oznacza to dużo I / O na początku i duże wykorzystanie pamięci, ponieważ pamięć podręczna każdego pracownika rośnie.mapowanie pamięciużywanie wątków zamiast procesówTo pytanie SO zasugerował również, że wiele problemów w świecie rzeczywistym, które wyglądają tak, jakby potrzebowały dostępu tylko do odczytudict
może się uruchomićfork()
kopiowanie na zapis, więc całkowite uniknięcie wykonywania kopii dużych obiektów może być niemożliwe.