import os, threading, Queue
def idmaker(aqueue):
while True:
u = hexlify(os.urandom(8)).decode('ascii')
aqueue.put(u)
idqueue = Queue.Queue(2)
t = threading.Thread(target=idmaker, args=(idqueue,))
t.daemon = True
t.start()
def idgetter():
return idqueue.get()
file d'attente est souvent la meilleure façon de synchroniser les threads en Python - qui est assez fréquent que lors de la conception d'un système multi-thread votre première pensée devrait être « la meilleure façon que je pourrais le faire avec Queues ». L'idée sous-jacente est de dédier un thread pour entièrement "posséder" une ressource ou un sous-système partagé, et tous les autres threads "worker" accèdent à la ressource uniquement par get et/ou puts sur Files d'attente utilisées par ce thread dédié (Queue est intrinsèquement threadsafe) .
Ici, nous faisons un idqueue
avec une longueur de seulement 2 (nous ne voulons pas la génération id pour se déchaîner, en faisant beaucoup de ids au préalable, ce qui gaspille la mémoire et épuise le réservoir d'entropie - pas sûr si 2
est optimal, mais le sweet spot va certainement être un petit entier ;-), donc le thread du générateur d'id va se bloquer en essayant d'ajouter le troisième, et attendre que de l'espace s'ouvre dans la file d'attente. idgetter
(qui peut aussi être simplement défini par une affectation de niveau supérieur, idgetter = idqueue.get
) trouvera normalement un identifiant déjà là et attendra (et fera de la place pour le prochain!) - sinon, il bloque et attend, se réveillant Dès que le générateur d'ID a placé un nouvel identifiant dans la file d'attente.
Pouvez-vous expliquer, s'il vous plaît, quelles sont les raisons pour éviter d'attraper IntegrityError (premier commentaire dans votre code)? La condition semble être un peu moins fiable, car il y a toujours une petite chance d'obtenir IntegrityError lors de l'exécution de la requête. Est-ce que ces raisons de performance? – Tony
@Anton certaines bases de données n'autorisent pas les instructions SQL suivantes après 'IntegrityError' jusqu'à la fin de la transaction. Vous devez donc revenir en arrière et répéter toutes les étapes depuis le début de la transaction. Ce n'est pas difficile dans certains cas particuliers (par exemple lorsqu'il n'y a pas d'autres requêtes dans la transaction), mais il n'y a pas de solution générale. La condition de course dans ma solution a une chance négligeable de se produire même une fois pour la vie de la plupart des projets. –