J'implémente une bibliothèque utilitaire qui est une sorte de gestionnaire de tâches destiné à fonctionner dans l'environnement distribué du service de cloud computing Google App Engine. (Il utilise une combinaison de files d'attente de tâches et de memcache pour exécuter le traitement de fond). Je prévois d'utiliser des générateurs pour contrôler l'exécution des tâches, en imposant essentiellement une "concurrence" non-préemptive via l'utilisation de yield
dans le code de l'utilisateur.
L'exemple trivial - le traitement d'un groupe d'entités de base de données - pourrait être quelque chose comme ce qui suit :
class EntityWorker(Worker):
def setup():
self.entity_query = Entity.all()
def run():
for e in self.entity_query:
do_something_with(e)
yield
Comme nous le savons, yield
est un canal de communication bidirectionnel, permettant de transmettre des valeurs au code qui utilise les générateurs. Ceci permet de simuler une "API préemptive" telle que la SLEEP
appel ci-dessous :
def run():
for e in self.entity_query:
do_something_with(e)
yield Worker.SLEEP, timedelta(seconds=1)
Mais c'est moche. Ce serait bien de cacher le yield
dans une fonction distincte qui peut être invoquée de manière simple :
self.sleep(timedelta(seconds=1))
Le problème est que mettre yield
en fonction sleep
tourne il en une fonction de générateur. L'appel ci-dessus renverrait donc simplement un autre générateur. Ce n'est qu'après avoir ajouté .next()
y yield
en arrière, nous obtiendrions le résultat précédent :
yield self.sleep(timedelta(seconds=1)).next()
qui est bien sûr encore plus laid et inutilement verbeux qu'avant.
D'où ma question : Y a-t-il un moyen de mettre yield
en fonction sans la transformer en fonction de générateur mais en la rendant utilisable par d'autres générateurs pour produire des valeurs calculées par elle ?