J'utilise python 2.7, j'ai du code qui ressemble à ceci:
task1()
task2()
task3()
dependent1()
task4()
task5()
task6()
dependent2()
dependent3()
Les seules dépendances ici sont les suivantes: dependante1 doit attendre les tâches 1-3, dependante2 doit attendre les tâches 4-6 et dependante3 doit attendre les dépendantes1-2 ... Ce serait bien: exécuter les 6 tâches en premier en parallèle, puis les deux premières personnes à charge en parallèle .. puis la dernière personne à charge
Je préfère avoir autant de tâches que possible en parallèle, j'ai cherché sur Google pour certains modules mais j'espérais éviter les bibliothèques externes, et je ne sais pas comment la technique de file d'attente peut résoudre mon problème (peut-être que quelqu'un peut recommander une bonne ressource ?)
La classe intégrée threading.Thread offre tout ce dont vous avez besoin: start pour démarrer un nouveau thread et join pour attendre la fin d'un thread.
import threading
def task1():
pass
def task2():
pass
def task3():
pass
def task4():
pass
def task5():
pass
def task6():
pass
def dep1():
t1 = threading.Thread(target=task1)
t2 = threading.Thread(target=task2)
t3 = threading.Thread(target=task3)
t1.start()
t2.start()
t3.start()
t1.join()
t2.join()
t3.join()
def dep2():
t4 = threading.Thread(target=task4)
t5 = threading.Thread(target=task5)
t4.start()
t5.start()
t4.join()
t5.join()
def dep3():
d1 = threading.Thread(target=dep1)
d2 = threading.Thread(target=dep2)
d1.start()
d2.start()
d1.join()
d2.join()
d3 = threading.Thread(target=dep3)
d3.start()
d3.join()
Sinon, pour rejoindre, vous pouvez utiliser Queue.join pour attendre la fin des threads.
Si vous êtes prêt à essayer les bibliothèques externes, vous pouvez exprimer les tâches et leurs dépendances avec élégance avec Ray . Cela fonctionne bien sur une seule machine, l'avantage ici est que le parallélisme et les dépendances peuvent être plus faciles à exprimer avec Ray qu'avec le python multiprocessing et qu'il n'a pas le problème GIL (Global Interpreter Lock)) cela empêche souvent le multithreading de fonctionner efficacement. De plus, il est très facile d'augmenter la charge de travail sur un cluster si vous en avez besoin à l'avenir.
La solution ressemble à ceci:
import ray
ray.init()
@ray.remote
def task1():
pass
@ray.remote
def task2():
pass
@ray.remote
def task3():
pass
@ray.remote
def dependent1(x1, x2, x3):
pass
@ray.remote
def task4():
pass
@ray.remote
def task5():
pass
@ray.remote
def task6():
pass
@ray.remote
def dependent2(x1, x2, x3):
pass
@ray.remote
def dependent3(x, y):
pass
id1 = task1.remote()
id2 = task2.remote()
id3 = task3.remote()
dependent_id1 = dependent1.remote(id1, id2, id3)
id4 = task4.remote()
id5 = task5.remote()
id6 = task6.remote()
dependent_id2 = dependent2.remote(id4, id5, id6)
dependent_id3 = dependent3.remote(dependent_id1, dependent_id2)
ray.get(dependent_id3) # This is optional, you can get the results if the tasks return an object
Vous pouvez également passer des objets python réels entre les tâches en utilisant les arguments à l'intérieur des tâches et en renvoyant les résultats (par exemple en disant "valeur de retour" au lieu de "passer" ci-dessus).
En utilisant "pip install ray", le code ci-dessus fonctionne dès le départ sur une seule machine, et il est également facile de paralléliser des applications sur un cluster, que ce soit dans le cloud ou dans votre propre cluster personnalisé, voir https: // ray.readthedocs.io/en/latest/autoscaling.html et https://ray.readthedocs.io/en/latest/using-ray-on-a-cluster.html ) . Cela pourrait être utile si votre charge de travail augmente plus tard.
Avertissement: je suis l'un des développeurs de Ray.
Regardez Gevent .
Exemple d'utilisation:
import gevent
from gevent import socket
def destination(jobs):
gevent.joinall(jobs, timeout=2)
print [job.value for job in jobs]
def task1():
return gevent.spawn(socket.gethostbyname, 'www.google.com')
def task2():
return gevent.spawn(socket.gethostbyname, 'www.example.com')
def task3():
return gevent.spawn(socket.gethostbyname, 'www.python.org')
jobs = []
jobs.append(task1())
jobs.append(task2())
jobs.append(task3())
destination(jobs)
J'espère que c'est ce que vous cherchiez.