Heim  >  Artikel  >  Backend-Entwicklung  >  Analyse von Missbrauchspunkten in der .Net-Multithread-Programmierung

Analyse von Missbrauchspunkten in der .Net-Multithread-Programmierung

怪我咯
怪我咯Original
2017-04-10 10:59:311959Durchsuche

In diesem Artikel wird hauptsächlich die Analyse von Missbrauchspunkten in der .Net-Multithread-Programmierung vorgestellt. Es hat einen bestimmten Referenzwert, schauen wir uns das unten mit dem Editor an

1 Problem mit gemeinsam genutzten Variablen

Falsche Schreibweise:

Alle Aufgaben können dieselbe Variable verwenden, sodass die Ausgabeergebnisse möglicherweise gleich sind.

public static void Error()
{
   for(int i=0;i<10;i++)
   {
    Task.Run(() => { Console.WriteLine("{0}", i); });
   }
}

Richtige Schreibweise:

Variable i der lokalen Variablen temp zuweisen, sodass jede Aufgabe einen anderen i-Wert verwendet.

public static void Right()
{
   for (int i = 0; i < 10; i++)
   {
    int temp = i;
    Task.Run(() => { Console.WriteLine("{0}", temp); });
   }
}

2 Durch ausstehende Aufgaben benötigte Ressourcen nicht bereinigen

Falsch Schreiben:

Textinhalt asynchron ausgeben, sodass die Variable sr vor der Verwendung von StreamReader ihren Gültigkeitsbereich verlassen hat und die Dispose-Methode aufgerufen wird.

public static void Error()
{
   using (StreamReader sr = new StreamReader(@"D:\说明.txt", Encoding.Default))
   {
    Task.Run(() => { Console.WriteLine("输出:{0}",sr.ReadLine()); });
   }
}

Richtiges Schreiben:

public static void Right()
{
   using (StreamReader sr = new StreamReader(@"D:\说明.txt", Encoding.Default))
   {
    var task = Task.Run(() => { Console.WriteLine("输出:{0}", sr.ReadLine()); });
    task.Wait();
   }
}

3 Vermeiden Sie das Sperren von this, typeof(type), string

Der richtige Ansatz: Definieren Sie ein privates schreibgeschütztes Feld vom Objekttyp und sperren Sie es.

4 Die Anzahl der WaitHandles in WaitHandle.WaitAll muss kleiner oder gleich 64 sein

public static void Error()
{
   ManualResetEvent[] manualEvents = new ManualResetEvent[65];

   try
   {
    for (int i = 0; i < 65; i++)
    {
     var temp = i;
     Task.Run(() =>
     {
      manualEvents[temp] = new ManualResetEvent(false);
      Console.WriteLine("{0}", temp);
      manualEvents[temp].Set();
     });
    }
    WaitHandle.WaitAll(manualEvents);
   }
   catch (Exception ae)
   {
    Console.WriteLine(ae.Message);
   }
}

5 Ausnahme kann nicht abgefangen werden

try
{
    var task = Task.Run(() => { throw new Exception("抛异常"); });
    //如果将下面这行代码注掉,则无法抛出异常
    task.Wait();
}
catch(Exception ex)
{
    Console.WriteLine(ex.Message);
}

6 Sollten Aufgabenressourcen freigegeben werden?

Es wird empfohlen, Dispose aufzurufen, ein Nichtaufruf ist jedoch kein schwerwiegender Fehler.

Beachten Sie, dass Ressourcen nicht freigegeben werden dürfen, wenn sich die Aufgabe in bestimmten Zuständen befindet, andernfalls wird ein Fehler gemeldet.

public static void CatchException()
{
   try
   {
    Console.WriteLine("开始");
    var task = Task.Run(() =>
    {
     //throw new Exception("抛异常"); 
    });
    //注掉下面这行代码,观察异常结果
    //task.Wait();
    task.Dispose();
    Console.WriteLine("结束");
   }
   catch(Exception ex)
   {
    Console.WriteLine(ex.Message);
   }
}

7 Deadlock-Demonstration

Angenommen, tsak1 und task2 If Nachdem die erste Sperre erfolgreich erhalten wurde, bevor die zweite Sperre erhalten wurde (für tsak1 ist die zweite angeforderte Sperre LockedObj2 und für task2 LockedObj1), kommt es zu einem Deadlock.

private static readonly Object LockedObj1 = new object();
private static readonly Object LockedObj2 = new object();
public static void LockShow()
{
   var task1 = Task.Run(() => 
   {
    lock (LockedObj1)
    {
     Console.WriteLine("get LockedObj1");
     lock (LockedObj2)
     {
      Console.WriteLine("get LockedObj2....");
     }
    }
   });
   var task2 = Task.Run(() =>
   {
    lock (LockedObj2)
    {
     Console.WriteLine("get LockedObj2");
     lock (LockedObj1)
     {
      Console.WriteLine("get LockedObj1....");
     }
    }
   });
}

Mehrere Durchläufe können zu den folgenden zwei Ergebnissen führen: Das erste Bild zeigt eine Situation, in der kein Deadlock auftritt, und das zweite Bild zeigt einen Deadlock Es kommt zu einer Sperrsituation.

8 Rufen Sie nicht die Thread.Abort-Methode auf.

Task stellt die Abort-Methode nicht zur Verfügung. Wenn Sie die neue TPL (nach .NET 4.0) verwenden, wird dieses Problem im Allgemeinen nicht zur Steuerung des Abbruchs von Aufgaben verwendet.

9 Stellen Sie sicher, dass gemeinsam genutzte Variablen sicher sind

Führen Sie es wiederholt aus. Sie können unterschiedliche Ergebnisse beobachten, wie in der Abbildung unten gezeigt.

public static void Func()
{
   string s = "ASDFGH";
   Parallel.Invoke(
    () => { s = s.Replace("A", "1"); s = s.Replace("S", "1s"); }, 
    () => { s = s.Replace("A", "2"); s = s.Replace("S", "2s"); }, 
    () => { s = s.Replace("A", "3"); });
   Console.WriteLine(s);
}

10 Prozessorüberbelegung und Unterauslastung

public static void Func()
{
   ParallelOptions po = new ParallelOptions();
   //超额申请,处理器只有4个逻辑内核,结果设置并行度为10且是个逻辑内核均在工作,等待的任务数量大于0.
   po.MaxDegreeOfParallelism = 10;
   //申请不足,处理器有4个逻辑内核,却指定并行度为3,还有一个空闲的内核没有被占用(也有可能被其他线程占用,这里假设在指定并行度为3的情况下,另一个内核空闲)
   po.MaxDegreeOfParallelism = 3;
   List<int> list = new List<int>();
   Parallel.ForEach(list, po, m =>
   {
    //业务
   });
}

Das obige ist der detaillierte Inhalt vonAnalyse von Missbrauchspunkten in der .Net-Multithread-Programmierung. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn