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.

tło

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ę taksocialisti wiesz o tym! ”. Jeśli słownik jest rozsądny, klasyfikator będzie ogólnie lepiej działać.

Pseudo kod
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
Problem

Powyż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.

Pytanie

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ów

To 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.

questionAnswers(1)

yourAnswerToTheQuestion