2010-02-01 9 views
6

to pytanie dotyczy kar za występowanie, które mogą, ale nie muszą, wynikać z posiadania dużej liczby śpiących wątków Pythona na serwerze internetowym.Python: kara za zasypianie wątków

Tło: Wdrażam sklep internetowy, używając django/satchmo. Wymóg dotyczy opóźnionej płatności. Klient może zarezerwować produkt i pozwolić stronie trzeciej na zapłacenie za niego w późniejszym terminie (za pośrednictwem losowego i unikalnego adresu URL).

Aby obsłużyć niezrezerwowanie przedmiotu, tworzę wątek, który będzie spać przez czas rezerwacji, a następnie usunie rezerwację/oznaczy produkt jako sprzedany, gdy się obudzi. Wygląda to tak:

#Reserves a product when it is placed in the cart 
def reserve_cart_product(product): 
    log.debug("Reserving %s" % product.name) 
    product.active = False 
    product.featured = False 
    product.save() 
    from threading import Timer 
    Timer(CART_RESERVE_TIME, check_reservation, (product,)).start() 

Używam tej samej techniki podczas uboju unikalnych adresów po ich wygaśnięciu, tylko Timer śpi znacznie dłużej (zwykle 5 dni).

Więc moje pytanie do was tak przedstawia się następująco:

jest posiadanie dużej numnber wątków wykraczających poważnie wpływa wydajność śpi? Czy istnieją lepsze techniki planowania jednorazowego wydarzenia w przyszłości? Chciałbym zachować to w pythonie, jeśli to możliwe; bez wywoływania at lub cron przez sys.

Strona nie jest dokładnie dużym natężeniem ruchu; górny limit produktów zamówionych w tygodniu wynosiłby około 100. W połączeniu z rezerwacją wózka może to oznaczać, że w danej chwili jest ponad 100 śpiworek. Czy będę żałować zadań planowania w ten sposób?

Dzięki

+1

Możesz potrzebować bardziej trwałego rozwiązania niż wątki na wypadek awarii serwera. O ile mogę powiedzieć, będziesz musiał przeszukać plik logu, aby stwierdzić, które produkty zostały zarezerwowane po awarii (choć nie będziesz wiedział, jak długo były zarezerwowane dla powyższego kodu). – tgray

+0

Dobrze trafiłeś i właśnie dlatego zacząłem zapisywać jakiś rekord w DB. – pisswillis

+0

Zakładasz, że twój serwer nie uruchomi się ponownie i nie dostaniesz tysięcy zamówień, prawda? Bardziej niezawodną opcją byłby stały system kolejkowania baz danych, taki jak RabbitMQ. –

Odpowiedz

7

Nie widzę powodu, dla którego to nie powinno działać. Podstawowy kod Timer (w threading.py) po prostu używa time.sleep. Kiedy już czeka na chwilę, to w zasadzie uruchamia pętlę z time.sleep (0.05) Powinno to spowodować użycie procesora w zasadzie 0%, nawet z setkami wątków. Oto prosty przykład, gdzie zauważyłem 0% użycia procesora przez proces Pythona:

import threading 

def nothing(): 
    pass 

def testThreads(): 
    timers = [threading.Timer(10.0, nothing) for _ in xrange(881)] 
    print "Starting threads." 
    map(threading.Thread.start, timers) 
    print "Joining threads." 
    map(threading.Thread.join, timers) 
    print "Done." 

if __name__ == "__main__": 
    testThreads() 

Prawdziwym problemem jest to, że może nie być w stanie zacząć zbyt wiele wątków. W 64-bitowym systemie 4 GB mogę uruchomić tylko 881 wątków, zanim wystąpi błąd. Jeśli naprawdę masz tylko kilkaset, nie mogę sobie wyobrazić, że to nie zadziała.

3

Zwykle wątki wątku nie mają narzutów poza pamięcią przeznaczoną na ich stosy i inne prywatne dane. Nowoczesne algorytmy szeregowania systemu operacyjnego mają złożoność O (1), więc nawet działający wątek nie wprowadza narzutów poza zasięgiem pamięci. Jednocześnie trudno sobie wyobrazić sprawne projektowanie wymagające wielu wątków. Jedyny przypadek, jaki mogę sobie wyobrazić, to komunikacja z wieloma innymi rówieśnikami. W takim przypadku należy użyć asynchronicznego IO.

4

100 wątków nie jest problemem, ale jako tgray pointed out, co się stanie, gdy serwer ulegnie awarii (wyłączenie zasilania, zaplanowana konserwacja, awaria sprzętu itp.)?

Musisz przechowywać gdzieś informacje o przechowywaniu w bazie danych.

Następnie możesz mieć zadanie cron okresowo uruchamiać skrypt konserwujący na przykład, i nie musisz mieć wszystkie te wątki siedzące wokół.

Jeśli naprawdę nie chcesz używać cron, po prostu masz jeden wątek roboczy, który śpi przez minutę, a następnie sprawdza, czy którekolwiek z braków są należne.

Powiązane problemy