Magazine

python, thread et la classe Queue

Publié le 24 mai 2008 par Mikebrant

La classe Queue convient parfaitement au Design Pattern Producteur Consommateur .

Queue implante une file d'attente (FIFO, First In First Out ) .

Elle est parfaitement adaptée à l'échange entre les threads puisqu'elle est thread-safe (c'est à dire qu'elle gère elle-même les verrous) .

C'est pourquoi elle est aussi idéale pour le design pattern Producteur - Consommateur .
En effet, lorsque l'on va ajouter un élément dans notre file, on sera alors un producteur et,
quand on récupérera une donnée, on sera un consommateur .

Pour expliquer le fonctionnement de Queue ( qui est extrêmement simple) et de ce DP , on va prendre un exemple .

Un magasin met dans un de ses rayons des paquets de Schtroumpfs, il va le ré-approvisionner tous les n temps : Producteur .
Les clients, quant à eux, ne peuvent prendre un paquet de schtroumpfs que chacun à leur tour ( j'ai toujours trouvé ca très con que les gens se précipitent en même temps sur le même rayon, qui fait à peine 20 cm, un peu de civilité pardi ! ) : Consommateur .
Et bien entendu, quand le magasin ré-approvisionne le rayon, les clients ne peuvent pas prendre de paquets .

Et voilà le code qui suit :

#-*- coding:Utf-8 -*-
import random
from Queue import *
from threading import Thread
import time
enStock = Queue(10)#notre pile, qui peut contenir 10 éléments max( 0 pour enlever la limite)
class Magasin(Thread):
   """ Le 'producteur' : va remplir ses rayons de paquets de schtroumpfs """
   def __init__(self):
      self.ouvert = True
      Thread.__init__(self)
   def run(self):
      while self.ouvert :
        
         while not enStock.full() :
            try :
              
               enStock.put("ajout d'un paquet de schtroumpf",True,1000)
               ### le Magasin va ajouter un paquet dans le rayon, et s'il y a plus de place,
               ### va attendre pendant 1 seconde qu'un paquet soit acheté .
            except Full,e :
               print(" Il n'y a pas de place pour un paquet ! ");
            else:
               print(" On ajoute un paquet de schtroumpfs dans le rayon")
        
         time.sleep(10)
         #on attend 10 secondes avant que le magasin aille alimenter le rayon
     
class Client(Thread):
   """ le consommateur, va prendre un/des paquet(s) de schtroumpf """
   def __init__(self,faim,numero):
      self.jAiFaim = faim
      self.numero = numero
      Thread.__init__(self)
     
     
   def run(self):
      while self.jAiFaim :
         time.sleep(1)
         #le client arrive au bout d'une seconde au rayon
         ok=False
         paquet = random.randint(1,4)
         #nombre de paquet qu'il va prendre
         i=1
         print(" Le client n° "+str(self.numero)+" veut "+str(paquet)+" paquet(s) de schtroumpfs")
         while i<=paquet :
            try:
               enStock.get(True,500)
               ok = True
               print(" n° "+ str(self.numero) + " : Prend un paquet")
              
            except Empty, e:
               ok = False
               break
            else:
               i+=1
         if ok :
            print(" Il reste " + str( enStock.qsize() ) +" paquet(s) de schtroumpfs")
         else :
            print(" n° "+ str(self.numero) + " : Il n'y a pas assez de paquets")
         self.jAiFaim = False
if __name__=='__main__':
   magasin = Magasin()
   magasin.ouvert = True
   print("##### Le magasin ouvre ses portes #####")
   magasin.start()
  
   i=1
   while i < 10:
      Client(faim = True ,numero = i).start()
      i=i+1
  
   time.sleep(60)
   magasin.ouvert=False
   print("##### Le magasin ferme ses portes #####")

Et l'explication :
enStock sera la file contenant le nombre de paquets disponible dans le rayon, soit 10 maximum .
Magasin sera donc une classe threadée, qui quand est ouvert, va envoyer un employé, toutes les 10 secondes, si enStock n'est pas plein ( full() ) .
L'employé va donc utiliser la méthode put(monObjet,Attendre,temps) pour remplir le rayon.
put(monObjet,[Attendre,temps]) :
monObjet : l'élémént que l'on va ajouter dans notre file.
Attendre : un booléen (par défaut False), si on doit attendre ou pas n temps .
temps : en ms, si Attendre est à True, le temps maximum que l'on attendra afin de mettre notre élément dans la file .
Quand le rayon est plein et que l'employé essaye quand même de lui rajouter un paquet, une exception Full est lancée .

Les Clients eux aussi sont threadés , quand ils ont faim, ils vont mettre 1 seconde à arriver au rayon Schtroumpfs.
Ils vont alors prendre leurs paquets via la méthode get() d' enStock .

get(Attendre,temps) :Attendre : un booléen (par défaut False), si on doit attendre ou pas n temps .
temps : en ms, si Attendre est à True, le temps maximum que l'on attendra afin de prendre un élément de la file .

Quand le rayon est vide et que le client essaye d'en prendre un, une exception Empty est lancée.

Voilà , c'est terminé.
Remplacez donc la Queue par une Liste, par exemple et voyez la différence .


Retour à La Une de Logo Paperblog

LES COMMENTAIRES (1)

A propos de l’auteur


Mikebrant 9 partages Voir son profil
Voir son blog

l'auteur n'a pas encore renseigné son compte l'auteur n'a pas encore renseigné son compte

Dossiers Paperblog