2016-10-27 10 views
3

검색 알고리즘을 최적화하려고합니다. ADS 인터페이스를 통해 TwinCat 3에서 기호를 찾는데 사용하고 있습니다. 질문은 TwinCat과 관련이 없으므로 아직 겁 먹지 않습니다.TwinCat에서 non-binary treelike 구조를 여러개의 쓰레드가있는 C#

문제 : 기호가 한 번에로드되지 않습니다. TwinCatAds 라이브러리가 느린 로딩을 사용한다고 생각합니다. 심볼은 비 바이너리 균형 트리가 아닌 treelike 구조를가집니다.

해결책 : ADS에 두 개 이상의 스트림을 열 수 있습니다. 그리고 스트림을 여러 스레드로 처리하십시오.

질문은 첫 번째 레벨의 레벨을 프로세서 코어 수로 나눕니다. 그래서 나무의 균형이 맞지 않아 일부 쓰레드가 다른 쓰레드보다 빨리 끝납니다. 이 때문에 스레드간에 작업을 나누는 방법이 더 멋진 솔루션이 필요합니다.

추신 : 나는 Parallel.ForEach()를 사용할 수 없습니다. 스트림 때문에 단일 스레드 솔루션과 동일하거나 더 많은 시간이 소요됩니다.

내 테스트 코드는 이렇게 보입니다. 거대한 프로젝트의 모든 심볼을 계산합니다.

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:

당신이 (내가 사용하고 있음) 코드를 사용 TwinCat.Ads 버전 4.0.17.0을 실행하려고합니다. 그들은 NuGet과 함께 사용할 수있는 새로운 버전에서 무언가를 깨 버렸습니다.

답변

1

스레드 풀을 만들고 스레드 실행 상태 및 유휴 상태를 추적합니다. 각 분기마다 유휴 스레드가 있는지 확인하고 하위 분기에 스레드가 할당되어 있는지 확인합니다.