2016-10-27 1 views
3

Ich versuche, einen Suchalgorithmus zu optimieren, den ich verwende, um markierte Symbole in TwinCat 3 über die ADS-Schnittstelle zu finden. Die Frage ist nicht TwinCat-bezogen, also lass dich nicht abschrecken.Traverse nicht-binäre treelike Struktur von TwinCat mit mehreren Threads in C#

Die Probleme: Symbole werden nicht sofort geladen. Ich denke, die TwinCatAds-Bibliothek verwendet Lazy Loading. Symbole haben treelike Struktur von nicht-binären nicht ausgeglichenen Baum.

Die Lösung: Sie können mehr als einen Stream zu ADS öffnen. Und behandeln Sie die Streams in mehreren Threads.

Die Frage ist, ich teile die erste Ebene von Symbolen durch die Anzahl der Prozessorkerne. Da der Baum unausgeglichen ist, enden einige der Threads schneller als die anderen. Aus diesem Grund brauche ich eine bessere Lösung, um die Arbeit zwischen den Fäden zu teilen.

PS: Ich kann die Parallel.ForEach() nicht verwenden. Aufgrund der Ströme ergibt sich dieselbe oder eine größere Zeitmenge wie bei der Lösung mit einem einzelnen Thread.

Mein Testcode sieht so aus, es zählt nur alle Symbole eines großen Projekts.

using TwinCAT.Ads; 
using System.Threading; 
using System.IO; 
using System.Diagnostics; 
using System.Collections; 


namespace MultipleStreamsTest 
{ 
class Program 
{ 
    static int numberOfThreads = Environment.ProcessorCount; 
    static TcAdsClient client; 
    static TcAdsSymbolInfoLoader symbolLoader; 
    static TcAdsSymbolInfoCollection[] collection = new TcAdsSymbolInfoCollection[numberOfThreads]; 
    static int[] portionResult = new int[numberOfThreads]; 
    static int[] portionStart = new int[numberOfThreads]; 
    static int[] portionStop = new int[numberOfThreads]; 

    static void Connect() 
    { 
     client = new TcAdsClient(); 
     client.Connect(851); 
     Console.WriteLine("Conected "); 
    } 
    static void Main(string[] args) 
    { 
     Connect(); 
     symbolLoader = client.CreateSymbolInfoLoader(); 
     CountAllOneThread(); 
     CountWithMultipleThreads(); 
     Console.ReadKey(); 
    }   
    static public void CountAllOneThread() 
    { 
     Stopwatch stopwatch = new Stopwatch(); 
     int index = 0; 
     stopwatch.Start(); 
     Console.WriteLine("Counting with one thread..."); 
     //Count all symbols 
     foreach (TcAdsSymbolInfo symbol in symbolLoader) 
     {     
      index++; 
     } 
     stopwatch.Stop(); 
     //Output 
     Console.WriteLine("Counted with one thred " + index + " symbols in " + stopwatch.Elapsed); 
    } 
    static public int countRecursive(TcAdsSymbolInfo symbol) 
    { 
     int i = 0; 
     TcAdsSymbolInfo subSymbol = symbol.FirstSubSymbol; 
     while (subSymbol != null) 
     { 
      i = i + countRecursive(subSymbol); 
      subSymbol = subSymbol.NextSymbol; 
      i++; 
     } 
     return i; 
    } 
    static public void countRecursiveMultiThread(object portionNum) 
    { 
     int portionNumAsInt = (int)portionNum; 
     for (int i = portionStart[portionNumAsInt]; i <= portionStop[portionNumAsInt]; i++) 
     { 
       portionResult[portionNumAsInt] += countRecursive(collection[portionNumAsInt][i]);//Collection Teil 
     } 
    } 
    static public void CountWithMultipleThreads() 
    { 
     Stopwatch stopwatch = new Stopwatch(); 
     int sum = 0; 
     stopwatch.Start(); 
     Console.WriteLine("Counting with multiple thread..."); 
     for (int i = 0; i < numberOfThreads; i++) 
     { 
      collection[i] = symbolLoader.GetSymbols(true); 
     } 
     int size = (int)(collection[0].Count/numberOfThreads); 
     int rest = collection[0].Count % numberOfThreads; 
     int m = 0; 
     for (; m < numberOfThreads; m++) 
     { 
      portionStart[m] = m * size; 
      portionStop[m] = portionStart[m] + size - 1; 
     } 
     portionStop[m - 1] += rest; 

     Thread[] threads = new Thread[numberOfThreads]; 
     for (int i = 0; i < numberOfThreads; i++) 
     { 
      threads[i] = new Thread(countRecursiveMultiThread); 
      threads[i].Start(i); 
      Console.WriteLine("Thread #" + threads[i].ManagedThreadId + " started, fieldIndex: " + i); 
     } 
     //Check when threads finishing: 
     int threadsFinished = 0; 
     bool[] threadFinished = new bool[numberOfThreads]; 
     int x = 0; 
     while (true) 
     { 
      if (threads[x].Join(10) && !threadFinished[x]) 
      { 
       Console.WriteLine("Thread #" + threads[x].ManagedThreadId + " finished ~ at: " + stopwatch.Elapsed); 
       threadsFinished++; 
       threadFinished[x] = true;      
      } 
      x++; 
      x = x % numberOfThreads; 
      if (threadsFinished == numberOfThreads) break; 
      Thread.Sleep(50); 
     }    
     foreach (int n in portionResult) 
     { 
      sum += n; 
     } 
     sum += collection[0].Count; 
     stopwatch.Stop(); 
     //Output 
     Console.WriteLine("Counted with multiple threds in Collection " + sum + " symbols " + " in " + stopwatch.Elapsed); 
     for (int i = 0; i < numberOfThreads; i++) 
     { 
      Console.WriteLine("#" + i + ": " + portionResult[i]); 
     } 
    } 
} 
} 

The console output:

Wenn Sie den Code verwenden TwinCat.Ads Version 4.0.17.0 (das ich verwende) versuchen zu laufen. Sie haben in der neuen Version, die mit NuGet verfügbar ist, etwas kaputt gemacht.

Antwort

1

Machen Sie einen Thread-Pool und verfolgen Sie die laufenden Threads und den Leerlaufstatus. Überprüfen Sie bei jeder Verzweigung, ob Leerlauf-Threads vorhanden sind, wenn der Sub-Verzweigung ein Thread zugeordnet ist.