Ca peut venir de l'IO ou de Word. Pour l'Io, le mieux serait de générer des MemoryStreams dans les threads et de tous les envoyers vers un thread dédié aux tâches IO, qui s'occuperait de les persister. A tester...
Ca peut venir de l'IO ou de Word. Pour l'Io, le mieux serait de générer des MemoryStreams dans les threads et de tous les envoyers vers un thread dédié aux tâches IO, qui s'occuperait de les persister. A tester...
Bonjour,
Est ce que j'utilise correctement le thread pool ? je n'arrive pas de trouver une optimisation, merci d'avance de votre retour.
On t'a donné plusieurs pistes, est-ce que tu les as essayé ?
Une autre solution plus radicale pour gagner en performance : augmente les ressources de ta machine => passer à un quadro-core ou plus, changer le disque mécanique en un disque plus rapide, arrêter les processus et service qui ne servent à rien et consomme de la ressource, etc...
Ou change ton achitecture => faire exécuter le traitement sur un réseau distribué (donc sur des machines différentes), générer du CSV à place de faire du word etc...
Tu ne nous donnes aucune information sur ton environnement d'exécution que se soit matériel ou logiciel..
" Dis ce que tu veux qui insulte mon honneur car mon silence sera la réponse au mesquin.
Je ne manque pas de réponse mais : il ne convient pas aux lions de répondre aux chiens ! " [Ash-Shafi'i ]
Avant toute chose, tu sembles disposer d'un bon indicateur pour mesurer les performances, c'est déjà un bon point pour commencer à expérimenter.
Après, as-tu tenté ce que j'ai préconisé ? Un thread distinct pour l'IO, les Threadpools pour créer les objets (pas valable évidemment si tu ne sauvegardes un document que toutes les 30s mais absolument nécessaire si on parle de 10 documents par seconde) ?
EDIT : La remarque ci-dessous est fausse dans la version 4.0 du framework : le ThreadPool ajuste désormais le nombre de threads pour optimiser le débit (load balancing).
Ensuite... Regardes les propriétés de ThreadPool et réduit le nombre de threads pour qu'ils collent au nombre de processeurs logiques (nb de cores, doublé si hyperthreading) et vois quelle différence tu observes.
Après ça, y a t-il contention au niveau des verrous ou d'autres primitives de synchronisation ?
Enfin, s'il y a contention au sein de Word, c'est dans la documentation de ce dernier qu'il faut chercher. Mais, là, je ne connais pas.
Je fais tourner mon batch sur un serveur Xeon e5410 2,33go.
Je ne pense pas espérer une meilleur serveur, mais je souhaite optimiser le max, est ce que le pool thread est bien utilisé? Merci de votre retour.
C'est cela le problème avec des spécifications non fonctionnelles. Le max c'est combien ? Qu'est-ce qui est acceptable ? Tu as l'air de dire 15 minutes comme si 30 minutes ou 1H cela poserait un problème majeur (tu ne programmes pas avec de vraies contraintes temps réel)
Et sinon tu n'as pas répondu à ma question, est-ce que tu peux utiliser et tester le framework 4 avec toutes ces nouveautés sur le multithreading ? Notamment les TPL Dataflow.. Au final on s'apercevrait que c'est un problème IO lié à Word..
" Dis ce que tu veux qui insulte mon honneur car mon silence sera la réponse au mesquin.
Je ne manque pas de réponse mais : il ne convient pas aux lions de répondre aux chiens ! " [Ash-Shafi'i ]
Ton ThreadPool n'est effectivement pas utilisé au mieux. Là, tu enfiles 4 tâches qui, chacune, traitent un quart des documents. Donc 4 threads seulement alors que tu dois avoir huit coeurs logiques sur ta machine pour commencer, et quand par ailleurs il est tout à fait possible qu'une tâche se termine après une heure seulement (parce qu'il lui a été attribué des documents plus petits) quand les autres continueront à mouliner. Un bon usage serait de créer une tâche (WorkItem) par document.
Ensuite, tu instancies dès le début des instances Word, plutôt que de le faire au fur et à mesure.
Tout cela étant dit, tu dois pouvoir obtenir un gain de deux ou trois. Sauf, bien sûr s'il y a contention au niveau de Word ou de l'IO, auquel cas tu ne gagneras rien.
EDIT : Le paragraphe ci-dessous est faux dans la version 4.0 du framework : le ThreadPool ajuste désormais le nombre de threads pour optimiser le débit (load balancing).
Enfin, Hegros a raison, l'usage de Task (dotnet framework 4) serait une bonne chose ici, préférable au ThreadPool : le principe reste le même le nombre de threads est automatiquement équilibré alors que, pour un ThreadPool, il est fixe (16 par défaut si tu as plus de 16 tâches ; ce nombre peut être changé, j'en parlais précédemment).
Comment j'utilise le thread pool avec efficacité? merci d'avance.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25 private class WorkItemData { public string File { get; set; } public ManualResetEvent Event { get; set; } } public static void Main() { var events = new List<WaitEventHandle>(); foreach (string file in GetFilesToProcess()) { var e = new ManualResetEvent(false); events.Add(e); ThreadPool.QueueUserWorkItem(ProcessFile, new WorkItemData { File = file, Event = e }); } WaitHandle.WaitAll(events.ToArray()); } public static void ProcessFile(Object threadContext) { var data = (WorkItemData)threadContext; ... data.Event.Set(); }
Je tiens à préciser que la taille des documents est identique pour les 4 threads, est ce qu'il est conseillé d'utiliser 4 autres threads (8 en tout), merci.
Il est rien conseillé du tout!
L'interet du ThreadPool contrairement à lancer toi même des threads, c'est que c'est le système qui gère le nombre de threads concurrents! Et cela en fonction de divers paramètres comme ta configuration machine, les autres threads d'autres programmes, les threads de ton programme que tu ne soupconnes pas qu'ils existent, etc.
Tu peux bien mettre 50 tâches dans le threadpool, si le système détermine que le niveau de concurrence optimum est à 6, il traitera 6 tâches en parallèle!
Le mieux est de découper des unités de code les plus fines et les plus parallèlisables.
Retrouvez moi sur :
Mon Espace Developpez.com------------------------------- Dvp.NET, une librairie open-source de composants .NET
Mon blog: Up there in the code---------------------------- Twitter: NatMarchand
Ma société: So@t
Showrizo : Suivez votre planning de séries télé sous Windows 8
Je vous remercie, désolé mais je n'ai pas réussi à faire fonctionner le bout de code :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54 public void FUSION(string s) { Console.Write("1"); String[] tbStr2 = s.Split(new Char[] { ';' }); string nb = tbStr2[0]; Object oMissing = System.Reflection.Missing.Value; Object oTrue = true; Object oFalse = false; Microsoft.Office.Interop.Word.Application oWord = new Microsoft.Office.Interop.Word.Application(); Microsoft.Office.Interop.Word.Document oWordDoc = new Microsoft.Office.Interop.Word.Document(); oWord.Visible = true; oWord.Visible = false; Object oTemplatePath = modelee; oWordDoc = oWord.Documents.Add(ref oTemplatePath, ref oMissing, ref oMissing, ref oMissing); bool sympb = false; bool E = false; bool n = false; bool p = false; bool r = false; foreach (Microsoft.Office.Interop.Word.Range range in oWordDoc.Words) {if (range.Text.Trim().Contains("$$")) { int pos = range.Text.Trim().IndexOf("$$"); string str = range.Text.Trim().Replace("$$", ""); range.Text = str;} } Object oSaveAsFile ="./1.doc"; oWordDoc.SaveAs(ref oSaveAsFile, ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing); oWordDoc.Close(ref oFalse, ref oMissing, ref oMissing); oWord.Quit(ref oMissing, ref oMissing, ref oMissing); } static void Main(string[] args) { Program p = new Program(); Action<string> fct = p.FUSION; for (int i = 0; i < 10; i++) { parametree pa = new Program.parametree(); pa.T = i; ThreadPool.QueueUserWorkItem(state => fct("1;TEST")); } }
il entre pas dans la méthode FUSION, merci d'avance.
Comme je vous l'ai expliqué il faut mettre un event car là vous quittez la fonction main tout de suite après votre boucle donc votre programme se termine tout de suite et ne fait rien.
Mon exemple n'avait que pour but de vous montrer comment passer un paramètre string en utilisant Action ( d'ailleurs
ne sert à rien c'était un autre exemple)
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2 parametree pa = new Program.parametree(); pa.T = i;
" Dis ce que tu veux qui insulte mon honneur car mon silence sera la réponse au mesquin.
Je ne manque pas de réponse mais : il ne convient pas aux lions de répondre aux chiens ! " [Ash-Shafi'i ]
Ah ben mince alors... Quand j'ai vu ce que tu avais écrit, j'ai jeté un oeil suspicieux mais, après une recherche google, j'ai découvert que MS avait changé l'implémentation du ThreadPool dans la version 4.0 du framework pour ajouter un système de load balancing tel que tu le décris. Bon ben j'ai quelques posts à éditer pour le coup...
En même temps le PO n'a pas l'air d'utiliser le framework 4..
De plus le nombre de thread dans le ThreadPool reste paramétrable avec la méthode SetMax/SetMin ou dans le core.. Bref, La meilleure façon de faire du parallélisme aujourd'hui c'est avec la TPL sauf cas particulier où il n'y a pas de meilleur manière que de gérer des Threads à l'ancienne..
" Dis ce que tu veux qui insulte mon honneur car mon silence sera la réponse au mesquin.
Je ne manque pas de réponse mais : il ne convient pas aux lions de répondre aux chiens ! " [Ash-Shafi'i ]
" Dis ce que tu veux qui insulte mon honneur car mon silence sera la réponse au mesquin.
Je ne manque pas de réponse mais : il ne convient pas aux lions de répondre aux chiens ! " [Ash-Shafi'i ]
j'ai réussi de faire appel à la méthode FUSION, par contre j'ai l'impression que cette méthode est appelé plusieurs fois ( il y a une erreur de réécriture de fichiers déjà existants.), merci infiniment de votre aide.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65 static void Main(string[] args) { const int FibonacciCalculations = 4; Program[] fibArray = new Program[FUSIONSS.Count]; Random r = new Random(); Console.WriteLine("launching {0} tasks...", FibonacciCalculations); Program p = new Program(); Action<string> fct = p.FUSION; int ibn = -1; Program f1 = new Program(); foreach (string s in FUSIONSS) { ibn++; String[] tbStr2 = s.Split(new Char[] { ';' }); fibArray[ibn] = f1; doneEvents[ibn] = new ManualResetEvent(false); ThreadPool.QueueUserWorkItem(state => fct(ibn+";"+s)); } } public void FUSION(string s) { String[] tbStr2 = s.Split(new Char[] { ';' }); string nb = tbStr2[0]; Object oMissing = System.Reflection.Missing.Value; Object oTrue = true; Object oFalse = false; Microsoft.Office.Interop.Word.Application oWord = new Microsoft.Office.Interop.Word.Application(); Microsoft.Office.Interop.Word.Document oWordDoc = new Microsoft.Office.Interop.Word.Document(); oWord.Visible = true; oWord.Visible = false; Object oTemplatePath = modelee; oWordDoc = oWord.Documents.Add(ref oTemplatePath, ref oMissing, ref oMissing, ref oMissing); bool sympb = false; bool E = false; bool n = false; bool p = false; bool r = false; foreach (Microsoft.Office.Interop.Word.Range range in oWordDoc.Words) {if (range.Text.Trim().Contains("$$")) { int pos = range.Text.Trim().IndexOf("$$"); string str = range.Text.Trim().Replace("$$", ""); range.Text = str;} } Directory.CreateDirectory("./" + nb); Object oSaveAsFile = "./" + nb + "/" + nb + ".doc"; oWordDoc.SaveAs(ref oSaveAsFile, ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing); oWordDoc.Close(ref oFalse, ref oMissing, ref oMissing); oWord.Quit(ref oMissing, ref oMissing, ref oMissing); Initial.doneEvents[(int.Parse(nbn))].Set(); }
Je te suggère d'essayer ceci :
Quand tu utilises un lambda avec, en argument, la variable itérée dans ta boucle foreach, le compilateur passe une référence vers cette variable plutôt que sa valeur, si bien que les derniers items exécutés lisent la dernière valeur possible pour "s" plutôt que la valeur au moment où le lambda a été créé. Avec le changement ci-dessus, ce ne sera pas le cas.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2 string workItemArgument = ibn + ";" + s; ThreadPool.QueueUserWorkItem(state => fct(workItemArgument ));
Au pire, si ça ne fonctionnait toujours pas (on ne sait jamais), change FUSION pour qu'elle accepte un objet en argument et utilise ceci :
Code : Sélectionner tout - Visualiser dans une fenêtre à part ThreadPool.QueueUserWorkItem(FUSION, ibn + ";" + s);
Bonjour,
J'ai essayé avec :
j'ai une erreur de compilation :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 Program p = new Program(); Action<string> fct = p.FUSION; int ibn = -1; Program f1 = new Program(); foreach (string s in FUSIONSS) { ibn++; String[] tbStr2 = s.Split(new Char[] { ';' }); fibArray[ibn] = f1; doneEvents[ibn] = new ManualResetEvent(false); string ssd = ibn + ";" + s; ThreadPool.QueueUserWorkItem(fct, ssd); }Merci de votre aide.Error 5 Argument '1': cannot convert from 'System.Action<string>' to 'System.Threading.WaitCallback'
Vous avez un bloqueur de publicités installé.
Le Club Developpez.com n'affiche que des publicités IT, discrètes et non intrusives.
Afin que nous puissions continuer à vous fournir gratuitement du contenu de qualité, merci de nous soutenir en désactivant votre bloqueur de publicités sur Developpez.com.
Partager