2012-01-09 14 views
7

Napisałem około 50 zajęć, których używam do łączenia się i pracy ze stronami internetowymi za pomocą mechanizacji i wątków. Wszystkie działają równolegle, ale nie zależą od siebie nawzajem. Oznacza to, że 1 klasa - 1 strona - 1 wątek. Nie jest to szczególnie eleganckie rozwiązanie, szczególnie w przypadku zarządzania kodem, ponieważ wiele kodów powtarza się w każdej klasie (ale nie na tyle, aby przekształcić je w jedną klasę do przekazywania argumentów, ponieważ niektóre witryny mogą wymagać dodatkowego przetwarzania pobranych danych w środku metod - jak "login" - którego inni mogą nie potrzebować). Jak już powiedziałem, to nie jest eleganckie - Ale działa. Nie muszę dodawać, że z zadowoleniem przyjmuję wszystkie zalecenia, jak napisać to lepiej, bez stosowania 1 klasy dla każdego podejścia do strony internetowej. Dodanie dodatkowej funkcjonalności lub całościowe zarządzanie kodami każdej klasy jest trudnym zadaniem.Jak zmniejszyć wykorzystanie pamięci przez kod z pytonem?

Jednak dowiedziałem się, że każdy wątek zajmuje około 8MB pamięci, więc przy 50 wątkach szukamy około 400MB użycia. Gdyby działał na moim systemie, nie miałbym z tym problemu, ale ponieważ działa na VPS z tylko 1GB pamięci, zaczyna to być problemem. Czy możesz mi powiedzieć, jak zmniejszyć zużycie pamięci lub czy istnieje inny sposób jednoczesnego działania z wieloma witrynami?

Użyłem tego szybkiego testu Pythona program do sprawdzenia, czy to dane przechowywane w zmiennych mojej aplikacji, która korzysta z pamięci, lub coś innego. Jak widać w poniższym kodzie, jest to tylko przetwarzanie funkcji uśpienia(), ale każdy wątek używa 8 MB pamięci.

from thread import start_new_thread 
from time import sleep 

def sleeper(): 
    try: 
     while 1: 
      sleep(10000) 
    except: 
     if running: raise 

def test(): 
    global running 
    n = 0 
    running = True 
    try: 
     while 1: 
      start_new_thread(sleeper,()) 
      n += 1 
      if not (n % 50): 
       print n 
    except Exception, e: 
     running = False 
     print 'Exception raised:', e 
    print 'Biggest number of threads:', n 

if __name__ == '__main__': 
    test() 

Kiedy uruchamiam to, wyjście jest:

50 
100 
150 
Exception raised: can't start new thread 
Biggest number of threads: 188 

I usuwając running = False linii, można następnie zmierzyć wolnej pamięci za pomocą polecenia free -m skorupek:

   total  used  free  shared buffers  cached 
Mem:   1536  1533   2   0   0   0 
-/+ buffers/cache:  1533   2 
Swap:   0   0   0 

Rzeczywisty Obliczenie, dlaczego wiem, że zabiera około 8 MB na wątek, jest wtedy proste, dzieląc różnicę pamięci używanej przed i podczas powyższej aplikacji testowej. g, podzielone przez maksymalne wątki, które udało mu się uruchomić.

To prawdopodobnie tylko pamięć przydzielona, ​​ponieważ patrząc na top, proces python wykorzystuje tylko około 0,6% pamięci.

+0

Co zajmuje pamięć? Zaryzykowałbym zgadnąć, że to dane, które wydobywacie z witryn. Jeśli tak jest, to prawdopodobnie nie ma zbyt wiele możliwości, aby dławić liczbę wykonywanych wątków. –

+0

Jak dokładnie mierzysz wykorzystanie pamięci? Przypuszczam, że te 8 MB nie są naprawdę przydzielone do każdego pojedynczego wątku. Ogromna część tych 8 MB może być dzielona między wątki (tylko odgadnięcie ..)? – Frunsi

+0

Demian i frunsi, zredagowałem moje pytanie, aby odpowiedzieć na oba pytania. Dzięki! – Gargauth

Odpowiedz

0

Nie jestem ekspertem od Pythona, ale może mam kilka pul wątków, które kontrolują całkowitą liczbę aktywnych wątków, i przekazuję "żądanie" do wątku, gdy skończy się już wątek. Żądanie nie musi być pełnym obiektem wątku, tylko tyle danych, aby wypełnić wszystkie żądania.

Można również zbudować strukturę, aby mieć pulę wątków A z N wątków pingujących stronę internetową, po pobraniu danych, przekazać dane do puli wątku B z wątkami Y chrupiącymi dane.

2

Stosowanie "jednego wątku na żądanie" jest proste i łatwe do zastosowania w wielu przypadkach. Jednak będzie to wymagało wielu zasobów (jak doświadczyłeś).

Lepszym rozwiązaniem jest użycie asynchronicznego, ale niestety jest to o wiele bardziej skomplikowane.

Niektóre wskazówki w tym kierunku:

+0

Dzięki, bardzo docenione. Czytałem wcześniej o Twisted, ale niestety nie wiem zbyt wiele na ten temat i dzięki temu nie byłbym w stanie zmechanizować go. Przyjrzę się, czy mogę zmechanizować pracę z asyncore. – Gargauth

+0

W końcu "idealnym" rozwiązaniem byłoby połączenie puli wątków z jednym wątkiem na rdzeń procesora (aby wykorzystać je do zadań przetwarzania) i asynchronicznego IO. Praktyczne rozwiązanie będzie zależeć od rzeczywistego kodu aplikacji. Być może nawet proste rozwiązanie oparte na 'select' zrobi to za Ciebie. – Frunsi

+1

Oznacza to: w swoim wątku: wyślij kilka żądań, następnie wprowadź pętlę, która "wybierze" na odpowiednich gniazdach i poradzi sobie z przychodzącymi danymi jeden po drugim ... i tak dalej. W końcu system operacyjny dba o gniazdo IO tak czy inaczej, Twoim zadaniem jest jak najłatwiejszy kontakt z systemem operacyjnym. – Frunsi

1

Rozwiązaniem jest zastąpienie kodu:

1) Czy coś .
2) Poczekaj, aż coś się wydarzy.
3) Zrób coś innego.

Z kodu:

1) coś zrobić.
2) Ułóż ją tak, aby po zrobieniu czegoś zostało zrobione.
3) Gotowe.

gdzieś indziej, masz kilka wątków, które to zrobić:

1) Czekaj na cokolwiek się wydarzy.
2) Zajmij się czymkolwiek.
3) Przejdź do kroku 1.

W pierwszym przypadku, jeśli czekasz na 50 rzeczy do zrobienia, masz 50 wątków siedzących czekając na 50 rzeczy, które się wydarzą. W drugim przypadku czeka na ciebie jeden wątek, który zrobi to, co 50 rzeczy, które musisz zrobić.

Nie używaj nici, aby poczekać, aż wydarzy się jedna rzecz. Zamiast tego, ułóż je tak, aby po tym wydarzeniu, jakaś inna nić zrobi wszystko, co trzeba, aby zrobić to dalej.

Powiązane problemy