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 .