2010-02-01 4 views
6

Cette question concerne les pénalités de performance qui peuvent découler ou non d'un grand nombre de threads python endormis sur un serveur Web. Contexte: J'implémente une boutique en ligne en utilisant django/satchmo. Une exigence est pour le paiement différé. Le client peut réserver un produit et permettre à un tiers de le payer à une date ultérieure (via une URL aléatoire et unique).Python: pénalité pour les threads dormants

Pour gérer un article sans réserve, je crée un fil qui dormira pendant la durée de la réservation, puis retirera la réservation/marquera le produit tel qu'il est vendu lorsqu'il se réveillera. Il ressemble à ceci:

#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() 

J'utilise la même technique lorsque les URL uniques culling après leur expiration, que la minuterie dort beaucoup plus longtemps (généralement 5 jours).

Alors, ma question est SO comme suit:

est d'avoir un grand numnber de fils allant dormir pour effectuer sérieusement les performances? Y a-t-il de meilleures techniques pour planifier un événement unique dans le futur? Je voudrais garder ceci en python si possible; aucun appel at ou cron via sys.

Le site n'est pas exactement à fort trafic; une limite supérieure (généreuse) sur les produits commandés par semaine serait d'environ 100. Combiné avec la réservation de chariot, cela pourrait signifier qu'il y a plus de 100 fils dormants à la fois. Est-ce que je regretterai de programmer des tâches de cette manière?

Merci

+1

Vous pouvez avoir besoin d'une solution plus persistante que les threads au cas où votre serveur tombe en panne. Autant que je sache, vous devrez rechercher votre fichier journal pour savoir quels produits ont été réservés après un plantage (bien que vous ne sachiez pas combien de temps ils ont été réservés avec le code ci-dessus). – tgray

+0

Vous faites un bon point et c'est pour cette raison que j'ai commencé à stocker des enregistrements dans la BD. – pisswillis

+0

Vous supposez que votre serveur ne redémarrera pas, et vous n'obtiendrez pas des milliers de commandes, n'est-ce pas? Une option plus robuste serait un système de mise en file d'attente de base de données persistante, tel que RabbitMQ. –

Répondre

7

je ne vois aucune raison pour laquelle cela ne devrait pas fonctionner. Le code sous-jacent de Timer (dans threading.py) utilise simplement time.sleep. Une fois qu'il a attendu pendant un certain temps, il exécute une boucle avec time.sleep (0.05) Cela devrait entraîner une utilisation du processeur de 0%, même avec des centaines de threads. Voici un exemple simple, où j'ai remarqué 0% l'utilisation du processeur pour le processus python:

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() 

Le vrai problème est que vous ne pouvez pas être en mesure de commencer réellement trop de threads. Sur mon système 4GB 64 bits, je ne peux démarrer que 881 threads avant d'avoir une erreur. Si vous n'en avez vraiment que quelques centaines, je ne peux pas imaginer que ça ne marchera pas.

3

Habituellement, les threads dormants n'ont pas de frais supplémentaires en dehors de la mémoire allouée pour leurs piles et d'autres données privées. Les algorithmes d'ordonnancement du système d'exploitation moderne ont une complexité O (1) donc même un thread en cours d'exécution n'introduit pas de surcharge, autre que l'empreinte mémoire. Dans le même temps, il est difficile d'imaginer une conception efficace nécessitant beaucoup de fils. Seul le cas que je peux imaginer est la communication avec de nombreux autres pairs. Dans ce cas, les entrées/sorties asynchrones doivent être utilisées.

4

100 threads ne pose aucun problème, mais en tant que tgray pointed out, que se passe-t-il si le serveur tombe en panne (coupure de courant, maintenance planifiée, défaillance matérielle, etc.)?

Vous devez stocker les informations de non-conservation dans votre base de données quelque part.

Ensuite, vous pouvez avoir un travail cron périodiquement déclencher un script d'annulation de réservation par exemple, et vous n'avez pas besoin d'avoir tous ces threads assis autour.

Si vous ne voulez vraiment pas utiliser cron, il suffit d'avoir un thread de travail qui dort pendant une minute, puis vérifie si l'une des réservations est due.

Questions connexes