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!