IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C# Discussion :

[C#] Question sur les threads et le nombre de calculs


Sujet :

C#

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre averti
    Inscrit en
    Juillet 2012
    Messages
    10
    Détails du profil
    Informations forums :
    Inscription : Juillet 2012
    Messages : 10
    Par défaut [C#] Question sur les threads et le nombre de calculs
    Bonjour,
    J'ai écrit quelques test dans une classe pour comparer le nombre d'opérations effectués sur une variable avec et sans multi thread de 3 manières différentes.

    Pour ces tests, j’utilise un processeur i3-2120 avec 2 cœurs et 4 threads (4 cpu visible dans le task manager).
    1) En utilisant le thread principal de l'application
    -> le résultat est plus ou moins stable en exécutant plusieurs fois le programme.
    2) En utilisant plusieurs thread et plusieurs variables que j’additionne à la fin.
    -> le résultat est complètement aléatoire avec des valeurs entre 100 et 250% (150% la plupart du temps) compare au premier test.
    3) en utilisant plusieurs thread mais une seule variable que je « lock » via la classe interlocked.
    -> le résultat est toujours plus petit que si je n’utilisais qu’un seul thread.

    Pour le 3eme résultat, je peux comprendre que le fait de verrouiller ma variable met un frein aux assignations dans les autres threads et qu’il soit donc normal que le résultat soit moins élevé que le test1.
    En revanche, pour le test 2, je ne comprends pas pourquoi les résultats varient autant et même en augmentant//diminuant le nombre de thread de traitement je n’arrive pas à obtenir un résultat a peu près égale a 400% compare au test 1.
    Je suis conscients que l’algo utilise n’est sans doute pas le plus optimise pour ce genre de test mais j’aimerais tout de même savoir pourquoi les résultats sont si diffèrent et si il y a un bon moyen d’exploiter toutes la puissance de calcul de mon processeur pour me rapprocher des 400%.
    Voici le code source pour mes tests :

    contenu de program.cs:
    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
     
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
     
    namespace csharpTests
    {
    	class Program
    	{
    		static void Main(string[] args)
    		{
    			//booltest.run();
    			cpuoverload.run();
    		}
    	}
    }
    contenu de cpuoverload.cs:
    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
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
     
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
     
    namespace csharpTests
    {
    	class cpuoverload
    	{
    		public static UInt64 globI = 0;
    		public static UInt64 globI1 = 0;
    		public static UInt64 globI2 = 0;
    		public static UInt64 globI3 = 0;
    		public static UInt64 globI4 = 0;
    		public static UInt64 globI5 = 0;
    		public static UInt64 globI6 = 0;
    		public static Int64 shared = 0;
     
    		/// <summary>
    		/// le run 1 se limite a 25% du cpu sur un quad core.
    		/// </summary>
    		public static void run1()
    		{
    			bool stop = false;
    			while (!stop)
    			{
    				++globI;
    			}
    		}
     
    		public static void run1_shared()
    		{
    			bool stop = false;
    			while (!stop)
    				System.Threading.Interlocked.Add(ref shared, 1);
    		}
     
    		public static void run1(object state)
    		{
    //			Console.WriteLine("ici state = {0}", state);
    			bool stop = false;
    			if (state != null)
    			{
    //				string tmp = (string)Convert.ChangeType(state, typeof(string));
    				string tmp2 = state as string;
    				switch (tmp2)
    				{
    					case "1":
    						while (!stop)
    							++globI1;						
    						break;
    					case "2":
    						while (!stop)
    							++globI2;						
    						break;
    					case "3":
    						while (!stop)
    							++globI3;
    						break;
    					case "4":
    						while (!stop)
    							++globI4;
    						break;
    					case "5":
    						while (!stop)
    							++globI5;
    						break;
    					case "6":
    						while (!stop)
    							++globI6;
    						break;
    				}
    			}
    			else
    			{
    				while (!stop)
    				{
    					++globI;
    				}
    			}
    		}
     
    		/// <summary>
    		/// le run 2 monte a ~30% sur un quad core et use deux process: conhost
    		///  ainsi que csrss
    		/// </summary>
    		public static void run2()
    		{
    			bool stop = false;
    			while (!stop)
    			{
    				Console.WriteLine(++globI);
    			}
    		}
    		/// <summary>
    		/// idem que run1, limite a 25% sur quad core meme avec un thread prio au plus haut.
    		/// </summary>
    		public static void run3()
    		{
    			System.Threading.Thread.CurrentThread.Priority = System.Threading.ThreadPriority.Highest;
    			bool stop = false;
    			UInt64 i = 0;
    			while (!stop)
    			{
    				++i;
    			}
    		}
     
    		/// <summary>
    		/// MAX CPU ~99%, lance le run1 dans plusieurs thread
    		/// </summary>
    		public static void run4()
    		{
    			System.Threading.Thread a = new System.Threading.Thread(new System.Threading.ThreadStart(run1));
    			System.Threading.Thread b = new System.Threading.Thread(new System.Threading.ThreadStart(run1));
    			System.Threading.Thread c = new System.Threading.Thread(new System.Threading.ThreadStart(run1));
    			System.Threading.Thread d = new System.Threading.Thread(new System.Threading.ThreadStart(run1));
    			a.Start();
    			b.Start();
    			c.Start();
    			d.Start();
    		}
    		public static void run4(object state)
    		{
    			System.Threading.Thread[] pool = state as System.Threading.Thread[];
    			pool[0].Start("1");
    			pool[1].Start("2");
    			pool[2].Start("3");
    			pool[3].Start("4");
    			pool[4].Start("5");
    			pool[5].Start("6");
    //			run1("4");
    		}
     
    		public static void run5(object state)
    		{
    			System.Threading.Thread[] pool = state as System.Threading.Thread[];
    			pool[0].Start();
    			pool[1].Start();
    			//pool[2].Start();
    			//pool[3].Start();
    			//pool[4].Start();
    			//pool[5].Start();
    			run1_shared();
    		}
     
    		/// <summary>
    		/// lance chaque run pour 5s et affiche le nombre d'op;
    		/// </summary>
    		public static void run()
    		{
    			globI = 0;
    			Console.WriteLine("start run1 for 5s ...", globI);
    			System.Threading.Timer t = new System.Threading.Timer(run1, null, 0, System.Threading.Timeout.Infinite);
    			System.Threading.Thread.Sleep(5000);
    			t.Dispose();
    			Console.WriteLine("{0} nbop", globI);
     
    			globI1 = 0;
    			globI2 = 0;
    			globI3 = 0;
    			globI4 = 0;
    			System.Threading.Thread a = new System.Threading.Thread(new System.Threading.ParameterizedThreadStart(run1));
    			System.Threading.Thread b = new System.Threading.Thread(new System.Threading.ParameterizedThreadStart(run1));
    			System.Threading.Thread c = new System.Threading.Thread(new System.Threading.ParameterizedThreadStart(run1));
    			System.Threading.Thread d = new System.Threading.Thread(new System.Threading.ParameterizedThreadStart(run1));
    			System.Threading.Thread e = new System.Threading.Thread(new System.Threading.ParameterizedThreadStart(run1));
    			System.Threading.Thread f = new System.Threading.Thread(new System.Threading.ParameterizedThreadStart(run1));
    			Console.WriteLine("start run4 for 5s ...");
    			t = new System.Threading.Timer(run4, new System.Threading.Thread[] {a,b,c,d, e, f}, 0, System.Threading.Timeout.Infinite);
    			System.Threading.Thread.Sleep(5000);
    			t.Dispose();
    			a.Abort();
    			b.Abort();
    			c.Abort();
    			d.Abort();
    			e.Abort();
    			f.Abort();
    			Console.WriteLine("{0} nbop = {1} + {2} + {3} + {4} + {5} + {6}", globI1 + globI2 + globI3 + globI4 + globI5 + globI6, globI1, globI2, globI3, globI4, globI5, globI6);
    			//System.Environment.Exit(42);
     
    			shared = 0;
    			a = new System.Threading.Thread(new System.Threading.ThreadStart(run1_shared));
    			b = new System.Threading.Thread(new System.Threading.ThreadStart(run1_shared));
    			c = new System.Threading.Thread(new System.Threading.ThreadStart(run1_shared));
    			d = new System.Threading.Thread(new System.Threading.ThreadStart(run1_shared));
    			e = new System.Threading.Thread(new System.Threading.ThreadStart(run1_shared));
    			f = new System.Threading.Thread(new System.Threading.ThreadStart(run1_shared)); 
    			Console.WriteLine("start run5 for 5s ...");
    			t = new System.Threading.Timer(run5, new System.Threading.Thread[] { a, b, c, d, e, f }, 0, System.Threading.Timeout.Infinite);
    			System.Threading.Thread.Sleep(5000);
    			t.Dispose();
    			a.Abort();
    			b.Abort();
    			c.Abort();
    			d.Abort();
    			e.Abort();
    			f.Abort();
    			Console.WriteLine("{0} nbop", System.Threading.Interlocked.Read(ref shared));
    		}
    	}
    }
    Merci d’avance pour vos réponses !

  2. #2
    Membre éclairé
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Février 2013
    Messages
    51
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2013
    Messages : 51
    Par défaut
    Bonjour,

    Je n'ai pas analysé en détails votre algo mais je pense qu'il y quelques pistes :
    - le fait de créer beaucoup de threads va demander beaucoup de changement de contexte,
    - à chaque changement de context, Windows peut choisir d'exécuter le code qu'il souhaite (donc pas forcément le vôtre),
    - Windows n'est pas un OS temps réel ce qui fait que les threads ne sont pas forcement exécutés dans l'ordre ou on l'attend

    Souvent pour traiter des données, il y a seuil dans le nombre de threads qu'il ne faut pas dépasser sous peine de voir les perfs se réduirent. Très souvent, il faut se limiter au threads "physiques" que peut gérer le CPU (donc 4 dans votre cas).
    Mais encore une fois, threading dans Windows = pas de temps réel !

  3. #3
    Expert confirmé Avatar de Graffito
    Profil pro
    Inscrit en
    Janvier 2006
    Messages
    5 993
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2006
    Messages : 5 993
    Par défaut
    1) En utilisant le thread principal de l'application
    -> le résultat est plus ou moins stable en exécutant plusieurs fois le programme.
    2) En utilisant plusieurs thread et plusieurs variables que j’additionne à la fin.
    -> le résultat est complètement aléatoire avec des valeurs entre 100 et 250% (150% la plupart du temps) compare au premier test.
    3) en utilisant plusieurs thread mais une seule variable que je « lock » via la classe interlocked.
    -> le résultat est toujours plus petit que si je n’utilisais qu’un seul thread.
    Le résultat 3) vs 1) est normal : c'est évidement le lock de la variable qui pénalise (un résultat compris entre 10% et 25% de la performance 1 me semble assez logique).

    Le résultat 2) vs 1) est plus difficile à comprendre : j'avais remarqué que sur 2 cores, un test de multithread ne donnnait aussi qu'un gain de l'ordre de 150%. Mais, je l'avais mis sur le compte des allocations mémoire. Ce n'est évidement pas le cas pour une simple incrémentation.
    Je pense que dans ce cas le goulet est l'accès physique à la mémoire. Il faudrait voir ce que ça donne avec plus d'instructions résultantes dans la boucle:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    while (true) globI=int.Parse((globi+1).ToString());

Discussions similaires

  1. Question sur les threads
    Par thebloodyman dans le forum Concurrence et multi-thread
    Réponses: 3
    Dernier message: 22/01/2007, 07h28
  2. Questions sur les threads: généralités
    Par Gragra dans le forum C++
    Réponses: 9
    Dernier message: 04/11/2006, 16h28
  3. Quelques questions sur les threads
    Par benj63 dans le forum C++Builder
    Réponses: 28
    Dernier message: 21/11/2005, 13h27
  4. Question sur les threads
    Par Linio dans le forum Concurrence et multi-thread
    Réponses: 10
    Dernier message: 21/10/2005, 09h08
  5. Question sur les threads
    Par nicolas66 dans le forum MFC
    Réponses: 4
    Dernier message: 03/06/2005, 20h57

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo