Accueil > .Net, C# > [C#4] Parallélisme – Episode 3

[C#4] Parallélisme – Episode 3

La revanche des threads !
Oups, pardon, je m’emporte.

Donc, quoi de neuf par rapport au dernier épisode ?
Une grosse bourde. Du coup, obligé d’amener les viennoiseries au taff… (d’ailleurs, les chouquettes, ça part incroyablement vite, je trouve…faudra débattre sur un autre sujet de l’intérêt d’amener des viennoiseries quand on casse un truc et aussi le succès des croissants/pains au chocolat/chouquettes.)

 

Résumé de la situation :
Sur mon application, j’ai utilisé beaucoup de parallélisme pour améliorer les temps de traitements.
Seulement, j’ai pas fais gaffe aux nombre de sessions oracle qui étaient créées.

Du coup, j’ai appris assez durement (une grande claque mentale dans la gueule) que la connexion en .Net était totalement décorrélée de la session oracle…

En développement, du fait du nombre d’utilisateurs limités et du volume « peu » important et aussi au fait que je travaillais sur la machine (donc que j’occupais les coeurs).

Par contre, sur une machine un peu puissante ou presque rien ne tourne… (faut imaginer une foule de plus en plus grosse qui demande en même temps à un pauvre agent SNCF quand arrivera le prochain train, à cause de cette foutu grève – je sais que vous pouvez imaginer…).
Le nombre de threads est alors assez important.
En fait, la base oracle a crié au secours, elle a appelé désespérément à l’aide, supplié, imploré et voyant que personne ne venait l’aider, elle a décider d’aller bouder dans son coin.
J’ai fais sauter les listeners, quoi….
Et là, y avait QUE deux coeurs…

Déjà, comment surveiller le nombre de sessions oracle ?
Via cette requête :

SELECT ROWNUM, username, osuser, program, status, state, event
 FROM v$session

Bien sûr, avec la clause where qui va bien, histoire de filtrer un peu.

Mais coté .Net, comment limiter ?
Par rapport au billet précédent, j’ai simplement supprimé le parallélisme pour la deuxième boucle (celle qui enregistre les fichiers).
Pour mémoire, c’est ce bout de code :

Parallel.ForEach(pjs.Keys, key =>
{
    i = 0;
    Parallel.ForEach(pjs[key], item =>
    {
        if (i++ % 100 == 0)
        {
            Console.WriteLine("Année {0}, fichier #{1} / {2} : {3}", key, i, pjs[key].Count, timerPJs.ElapsedMilliseconds);
        }
        item.SaveFile(dal);
    });
});

Qui devient :

Parallel.ForEach(pjs.Keys, key =>
{
    i = 0;
    foreach(Attachment item in pjs[key])
    {
        if (i++ % 100 == 0)
        {
            Console.WriteLine("Année {0}, fichier #{1} / {2} : {3}", key, i, pjs[key].Count, timerPJs.ElapsedMilliseconds);
        }
        item.SaveFile(dal);
    });
});

Du coup, j’ai du parallélisme uniquement sur les années (donc une session oracle par année).

Dans le cas où j’ai 10 années avec 30k fichiers par année, ça va.
Mais si j’ai 3 années avec 100K fichiers, c’est un peu le drame…

Idem s’il y a un gros déséquilibre sur le nombre de fichiers par année (10k sur l’une, 2k sur l’autre), la vitesse sera importante au départ puis plus lente au fil du temps.
Grosso modo, avec cette solution, j’ai autant de fichiers créé en même temps que nombre d’années.
Si j’ai 10 années, je vais commencer avec 10 fichiers créés à la fois, puis 9 quand la première année va être finie, puis 8, puis 7…jusqu’à ce qu’il ne reste que les années avec le plus grand nombre de fichiers (je reviens dessus pour une meilleure solution, un peu plus bas).

Sinon, on peut aussi limiter le degré de parallélisme.
Et là, on va voir du coté de ce billet.

Mais au final, une autre solution est de ne plus séparer par année, mais par lot.
Autrement dit, je construis une liste qui va contenir des listes de 5.000 fichiers.
Comme ça, pour 50k fichiers, je vais avoir 10 listes.
Je vais donc utiliser le parallélisme pour boucler sur chacun des lots, j’aurais donc – jusqu’au bout -, 10 sessions oracle au lieu d’en perdre au fil de l’eau.

Moralité : en utilisant le parallélisme, il faut vérifier que la machine sur laquelle on fait tourner l’appli puisse tenir, mais que c’est également le cas pour tous les différents flux dépendants (webservices, BDD, etc.).

 

Et vous, chouquettes, croissants, pains au chocolat, pains suisse ?

Catégories :.Net, C#
  1. Aucun commentaire pour l’instant.
  1. No trackbacks yet.

Laisser un commentaire

Entrez vos coordonnées ci-dessous ou cliquez sur une icône pour vous connecter:

Logo WordPress.com

Vous commentez à l'aide de votre compte WordPress.com. Déconnexion / Changer )

Image Twitter

Vous commentez à l'aide de votre compte Twitter. Déconnexion / Changer )

Photo Facebook

Vous commentez à l'aide de votre compte Facebook. Déconnexion / Changer )

Photo Google+

Vous commentez à l'aide de votre compte Google+. Déconnexion / Changer )

Connexion à %s

%d blogueurs aiment cette page :