Archive

Archive for juin 2011

Feeds Of The Week #3

La semaine dernière, j’étais un peu en vacances, donc j’ai…rien foutu. Faut l’admettre, mais c’est aussi fait pour ça, les vacances !

Donc, cette semaine, reprise assez douce.

Langage C#

Déjà, sur stackoverflow, un post bien utile, mine de rien : Hidden Features of C#?

Ensuite, les constructeurs privés, à quoi ça sert ? Comment bien les utiliser, qu’est ce qui fonctionne, fonctionne pas… Eh bien c’est là : Use of a Private Constructor.

Ensuite, un peu de Linq. En effet, à quoi sert la méthode Empty(), la méthode DefaultIfEmpty() et comment user intelligemment Count() et Any() ? C#/.NET Little Wonders: Empty(), DefaultIfEmpty(), and Count().

Et comme le blog est bien, on reste sur le même avec un point assez utile sur les différentes collections existantes (dont les collections concurrentes). C#/.NET Fundamentals: Choosing the Right Collection Class

Bonus

Là, c’est pour un peu plus que chose que simplement le codage.
Qui n’a jamais vu une taille en octets et a voulu avoir l’équivalent (rapidement) en d’autres mesures ?
Ou alors se demander si les gens à l’autre bout du monde était déjà présent pour faire une MEP tranquille ?
Ou alors quel était en millimètres la taille d’un papier « Double Elephant » ? (pour info : 678 x 1016).
Eh bien c’est ici : Convertworld.

Publicités
Catégories :.Net, Divers, Feeds

[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#