J'ai déja utilisé MPI en C++ et il y a un biding python. C'est un framework/protocole de communication (au dessus des sockets) qui permet de transmettre des messages de façon haut niveau (messages blocants/non blocants, thread safe, proche en proche ou broadcast, permet la création de groupe de communication, de plein de topologies de réseau, ...). De ce que je sais, Open MPI est très utilisé dans les clusters de calcul scientifiques.
Avantages :
* une fois installé sur toutes les machines et noté leur ip dans le fichier de config, tu lances un code, il se propage et communique sans emmerde
* hautement configurable (peut-être un inconvéniant dans ton cas)
Inconvéniants :
* la syntaxe fait un peu peur au début
* il n'utilises que des sockets (comme toutes les autres solutions proposées) ce qui fait un overhead par rapport à une utilisation des IPC si jamais tu l'utilises pour faire du multiprocessing sur une seule machine.
Exemple pris ici :
#!/usr/bin/env python
"""Demonstrate the task-pull paradigm for high-throughput computing
using mpi4py. Task pull is an efficient way to perform a large number of
independent tasks when there are more tasks than processors, especially
when the run times vary for each task.
This code is over-commented for instructional purposes.
This example was contributed by Craig Finch (cfinch@ieee.org).
Inspired by http://math.acadiau.ca/ACMMaC/Rmpi/index.html
"""
from mpi4py import MPI
def enum(*sequential, **named):
"""Handy way to fake an enumerated type in Python
http://stackoverflow.com/questions/36932/how-can-i-represent-an-enum-in-python
"""
enums = dict(zip(sequential, range(len(sequential))), **named)
return type('Enum', (), enums)
# Define MPI message tags
tags = enum('READY', 'DONE', 'EXIT', 'START')
# Initializations and preliminaries
comm = MPI.COMM_WORLD # get MPI communicator object
size = comm.size # total number of processes
rank = comm.rank # rank of this process
status = MPI.Status() # get MPI status object
if rank == 0:
# Master process executes code below
tasks = range(2*size)
task_index = 0
num_workers = size - 1
closed_workers = 0
print("Master starting with %d workers" % num_workers)
while closed_workers < num_workers:
data = comm.recv(source=MPI.ANY_SOURCE, tag=MPI.ANY_TAG, status=status)
source = status.Get_source()
tag = status.Get_tag()
if tag == tags.READY:
# Worker is ready, so send it a task
if task_index < len(tasks):
comm.send(tasks[task_index], dest=source, tag=tags.START)
print("Sending task %d to worker %d" % (task_index, source))
task_index += 1
else:
comm.send(None, dest=source, tag=tags.EXIT)
elif tag == tags.DONE:
results = data
print("Got data from worker %d" % source)
elif tag == tags.EXIT:
print("Worker %d exited." % source)
closed_workers += 1
print("Master finishing")
else:
# Worker processes execute code below
name = MPI.Get_processor_name()
print("I am a worker with rank %d on %s." % (rank, name))
while True:
comm.send(None, dest=0, tag=tags.READY)
task = comm.recv(source=0, tag=MPI.ANY_TAG, status=status)
tag = status.Get_tag()
if tag == tags.START:
# Do the work here
result = task**2
comm.send(result, dest=0, tag=tags.DONE)
elif tag == tags.EXIT:
break
comm.send(None, dest=0, tag=tags.EXIT)