Calculs parallèles en réseau
Nous avons développé un système de calculs parallèles en réseau simple et rapide utilisant .net remoting, particulièrementr adapté aux réseau locaux.
Ce système est composé :
- D'exécuteurs qui sont des services windows .net qui effectuent les calculs distribués, vous pouvez installer les exécuteurs sur n'importe quelle machine sous windows sur laquelle est installé le .net framework 2.0.
- D'un manager (un service windows nécessitant .net 2.0) qui maintient une liste d'exécuteurs disponibles et une librairie de routines de calculs.
- De clients qui effectuent les calculs parallèles aussi simplement que possible.
Fonctionnement :
- Chaque exécuteur indique périodiquement sa disponibilité au manager.
- Les exécuteurs sont automatiquement ùmis à jour à chaque fois qu'un changement intervient dans la librairie de routines de calculs du manager.
- Un client crée un tableau de paramètres à calculer indépendamment, demande au manager la liste des exécuteurs disponibles et demande ensuite à chaque exécuteur de calculer des éléments du tableau de paramètres. Tout ceci est effectué de manière transparente sans avoir à se préoccuper de la complexité des communications réseau ou de la synchronisation des tâches.
Quand tous les paramètres du tableau ont été calculés (un paramètre peut être une structure complexe) le client construit la solution finale (par exemple en agrégeant ou en moyennant les solutions élémentaires).
Le "framework" de développement:
- Les routines de calcul sont extrèmement simples, elle doivent hériter d'un clase de base et redéfinir une fonction ‘Calculate’ dont la sgnature est : public override object Calculate(object obj);
obj est un paramètre élémentaire (cela pourrait être un tableau d'autres objets) et la fonction doit retourner un solution élémentaire (qui peut aussi être un tableau d'autres objets). - Développer un client est très facile, voici un exemple de code :
using ZelGrid; using System.Runtime.Remoting; ... String ConfigFilePath = Path.GetDirectoryName(Application.ExecutablePath) + @"\Client.exe.config"; RemotingConfiguration.Configure(ConfigFilePath,false); ... long nbIter = 100000000; long nbCalc = 2000; zgs = new ZelGrid.CalcArray(@"tcp://{0}:9000/ZelExecutor", null, "PI_montecarlo", "PI_montecarlo.PI_montecarlo", ZelGrid.Calculator.TYPECALC.Standard); //Paramètres long i = 1; do { zgs.AddItem(nbIter); i += 1; } while (i <= nbCalc); //Calcul CalcArray.CALCRESULT resul = zgs.Calculate(true); //Résultat Double piEval=0.0; for (i = 0; i < nbCalc; i++) { object lRes = zgs.getResult(i); piEval=piEval+(double)lRes; } piEval = piEval / nbCalc;
using System; using ZelGrid; namespace PI_montecarlo { public class PI_montecarlo : ZelGrid.Std0Calculator { private Random rndNumbers; public PI_montecarlo(object dataIni): base(dataIni) { rndNumbers = new Random(); } public override object Calculate(object obj) { Double dres = 0.0; try { long nb = (long)obj; long nbin = 0; double dx = 0.0; double dy = 0.0; for (long i = 1; i <= nb; i++) { dx = rndNumbers.NextDouble(); dy = rndNumbers.NextDouble(); if (dx * dx + dy * dy <= 1) nbin = nbin + 1; } dres = 4.0 * nbin / nb; } catch (Exception) { return null; } return dres; } } }
Avantages :
- Développer des routines de calcul est très simple.
- Vous n'avez besoin que du .net framework 2.0, vous n'avez pas à installer de base de données sur le manager.
- Nous utilisons .Net remoting pour communiquer entre les ordinateurs et c'est la solution la plus rapide.
- Le programme est très stable.
- Si un exécuteur est arrêté durant un calcul celui se terminera correctement avec les exécuteurs restant. Si un nouvel exécuteur devient disponible pendant un calcul il sera inclus pour finir celui-ci.
- Les exécuteurs sont multitâches, si plusieurs clients demande l'exécution de calculs, ceux-ci seront effectués simultanément.
- Les exécuteurs s'exécutent par défaut avec une priorité faible (qui peut être modifiée), vous pouvez donc les installer sur des postes de travail sans ralentir ceux-ci.
- Vous pouvez développer facilement des enveloppes C# pour utiliser des routines existantes écrites en C ou C++.
- Vous pouvez développer des routines en IronPython (mais elles seront plus lentes) ou utiliser le "framework" depuis IronPython.
Si vous voulez tester :
Télécharger le fichier d'installation du manager : ZelManager.msi
Télécharger le fichier d'installation de l'exécuteur : ZelExecutor.msi
Télécharger l'exemple de client : Client.zip
Ce sont des versions de demonstration, les exécuteurs s'arrêteront au bout d'une heure (il faudra alors redémarrer le service) et les mise à jour automatiques ne sont pas activées.
Instructions d'installation :
- Installez d'abord le manager sur un ordinateur, choisissez un port tcp (9001 par défaut)
- Installez l'exécuteur sur d'autres ordinateurs (vous pouvez installer un exécuteur sur la machine sur laquelle vous avez installé le manager) en spécifiant le nom de la machine manager (ou son adresse ip) et le port tcp du manager (9001), choisissez un port tcp pour l'exécuteur (9000 par défaut), laissez vide "Update directory" (cela n'est pas utilisé dans la version de démonstration), cochez "use ip" si le client ne peut résoudre le nom des exécuteurs mais peut se connecter à leur adresse ip.
- Décompressez client.zip dans un dossier. Modifiez le fichier Client.exe.config : remplacez MANAGER par le nom de l'ordinateur manager ou son adresse ip dans la ligne suivante : tcp://MANAGER:9001/ZelManager/ZelManagerObj et modifiez la valeur clé "execport" si besoin est, pour la faire correspondre avec le port tcp utlisé par les exécuteurs.
- Ouvrez les pare-feux pour les ports TCP 9001 entre les executeurs et le manager et pour les port TCP 9000 entre le client et les exécuteurs.
Pour développer vos propres routines :
- Utilisez le .net framework 2.0, et partez de l'exemple pi_montecarlo ci-dessus.
- Copiez votre assemblée dans le répertoire ZelExecutor de chaque ordinateur exécuteur.
Pour développer un client:
- Importez l'assemblée ZelGrid
- Configurez .net remoting pour votre client
exemple: Vous pouvez utiliser un fichier de configuration
<configuration>
<system.runtime.remoting>
<application name = "ZelExecutor">
<client>
<wellknown
type="ZelGrid.ZelManagerObj, ZelGrid"
url="tcp://MANAGER:9001/ZelManager/ZelManagerObj"
/>
</client>
<channels>
<channel ref="tcp client" name="client"/>
</channels>
</application>
</system.runtime.remoting>
</configuration>
(MANAGER doit être remplacé par le nom de votre manager ou son adresse ip)
et le charger :
RemotingConfiguration.Configure(ConfigFilePath,false);
- Créez un tableau de paramètres
zgs = new ZelGrid.CalcArray(@"tcp://{0}:9000/ZelExecutor", //{0} sera remplacé automatiquement par le nom de chaque exécuteur disponible (ou son adresse ip).
null, //object : données qui peuvent être utilisées par le constructeur de votre routine de calcul
"PI_montecarlo", //Nom de l'assemblée de la routine de calcul sans son extension
"PI_montecarlo.PI_montecarlo", //Nom de la classe de la routine de calcul
ZelGrid.Calculator.TYPECALC.Standard); //executeur de type Standard (assemblée qui peut être chargée dynamiquement), IronPython (developpée en IronPython) ou NonStandard (rarement utilisé)
2 autres constructeurs sont disponibles : le premier spécifie un nombre de processeurs (de coeurs) demandé en dernier paramètre.
Le second spécifie le nom d'une machine en dernier paramètre (vous pouvez ainsi demander que telle machine effectue tel calcul).
Ajoutez des paramètres:
do { zgs.AddItem(object); ...} while (condition);
- Lancez le calcul
zgs.Calculate(true, //Est-ce un appel bloquant ?
0, //Timeout pour le calcul total (ms) pas de timeout si 0
0);//Timeout pour un calcul élémentaire (ms) pas de timeout si 0
retourne une valeur du type énuméré CALCRESULT {CalcOk,NoExecutorAvailable,TimeoutAllCalc};
- Analyser les resultats
for (i = 0; i < nbCalc; i++) { object lRes = zgs.getResult(i); ...}
- Si vous voulez des informations durant le calcul interrogez la propriété "infos" du tableau
for (int i = 0; i < zgs.infos.Count; i++) {long nbItemsCalculated = ((InfosMachine)zgs.infos.GetByIndex(i)).nbItems;} - Synchronisation des calculs :
Vous pouvez lancer plusieurs calculs avec différents tableaux de paramètres et les synchroniser à l'aide de la propriété m_Ended de type ManualResetEvent du tableau.
ex: zgs1.Calculate(false);
zgs2.Calculate(false);
zgs1.m_Ended.WaitOne();
zgs2.m_Ended.WaitOne();
zgs3.Calculate(false);
Attend que les calculs 1 et 2 soient terminés avant de lancer le calcul 3.
Contactez nous pour plus d'informations :