2013-05-02 2 views
2

동적으로 스레드에 대한 작업을 할당하는 클래스를 설정하는 방법을 알고 싶습니다. C#을 사용하는 것이 좋습니다. 레이 트레이서 설명을 위해 [this]을 보았습니다. 그러나 이것이 어떻게 보일지에 대한 설명도 보지 못했습니다. 나는 지나치게 복잡한 것을 원하지 않습니다.C#의 스레드에 대한 동적 작업 할당

너무 많은 작업 그룹이있어 균등하게 분할하여 내 스레드에 제공 할 수 없습니다. 각 스레드에 작업의 작은 부분을 동적으로 할당 한 다음 스레드가 완료되면 그 결과를 얻고 더 많은 작업을 제공하려고합니다. 나는 몇 년 전에 비슷한 일을했지만, 그 노트를 찾거나 구글이나 여기에서 성공하지 못했다.

도움을 주시면 감사하겠습니다.

아래는 의사 코드에서의 모습입니다. 그것은 예쁘게 보이지는 않을 것입니다.하지만 제가 말하는 것에 대한 아이디어를 줄 것입니다.

TaskList = ArrayList of n tasks 
ResultList = ArrayList of thread results 
create x threads 
integer TasksCompleted 
while(TasksCompleted < TaskList.size){ 
    thread = next available thread in pool 
    ResultList.add(thread.results) 
    tasksCompleted += thread.numOfTasks 
    thread.doWork(Next set of Tasks) 
} 
clean up threads 
processResults(ResultList) 
+0

[BlockingCollection] (http://msdn.microsoft.com/en-us/library/dd267312.aspx) 또는 .Net 4.5를 사용할 수 있는지 확인하십시오. [DataFlow Pipelines] (http://msdn.microsoft.com/en-us/library/hh228604.aspx) –

+1

[PLINQ] (http://msdn.microsoft.com/en-us/)에서보아야합니다. library/dd460688.aspx)이 정확한 시나리오를 위해 설계되었습니다. –

+1

설명하는 내용은 스레드 풀입니다. C#은 버전 2.0 이후로 스레드 풀이 있었지만 스레드 풀 위에 빌드 된 TPL 및 기타 고급 병렬 프로그래밍 도구를 추가하여 버전 4.0에서 기능이 크게 확장되었습니다. 이들이 자신의 스레드 풀을 작성하기 전에 필요한 것을 수행 할 수 없는지 확인하십시오. – Servy

답변

0

다음은 간단한 작업 대기열을 관리하기 위해 BlockingCollection을 사용하는 예입니다.

작업자 스레드가 현재 항목을 완료하면 작업 대기열에서 새 항목을 제거하고 해당 항목을 처리 한 다음 출력 대기열에 추가합니다.

개별 소비자 스레드는 완료된 항목을 출력 큐에서 제거하고 그와 함께 처리합니다.

출력 대기열을 완료 됨 (outputQueue.CompleteAdding())으로 표시하려면 모든 작업자가 완료 될 때까지 기다려야합니다 (Task.WaitAll(workers)).

이 예제에는 작업 항목에 대한 int 만 있습니다. 실제 코드에서는 작업을 캡슐화 한 객체를 사용합니다.

using System; 
using System.Collections.Concurrent; 
using System.Threading; 
using System.Threading.Tasks; 

namespace Demo 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      new Program().run(); 
     } 

     void run() 
     { 
      int threadCount = 4; 
      Task[] workers = new Task[threadCount]; 

      Task.Factory.StartNew(consumer); 

      for (int i = 0; i < threadCount; ++i) 
      { 
       int workerId = i; 
       Task task = new Task(() => worker(workerId)); 
       workers[i] = task; 
       task.Start(); 
      } 

      for (int i = 0; i < 100; ++i) 
      { 
       Console.WriteLine("Queueing work item {0}", i); 
       inputQueue.Add(i); 
       Thread.Sleep(50); 
      } 

      Console.WriteLine("Stopping adding."); 
      inputQueue.CompleteAdding(); 
      Task.WaitAll(workers); 
      outputQueue.CompleteAdding(); 
      Console.WriteLine("Done."); 

      Console.ReadLine(); 
     } 

     void worker(int workerId) 
     { 
      Console.WriteLine("Worker {0} is starting.", workerId); 

      foreach (var workItem in inputQueue.GetConsumingEnumerable()) 
      { 
       Console.WriteLine("Worker {0} is processing item {1}", workerId, workItem); 
       Thread.Sleep(100);   // Simulate work. 
       outputQueue.Add(workItem); // Output completed item. 
      } 

      Console.WriteLine("Worker {0} is stopping.", workerId); 
     } 

     void consumer() 
     { 
      Console.WriteLine("Consumer is starting."); 

      foreach (var workItem in outputQueue.GetConsumingEnumerable()) 
      { 
       Console.WriteLine("Consumer is using item {0}", workItem); 
       Thread.Sleep(25); 
      } 

      Console.WriteLine("Consumer is finished."); 
     } 

     BlockingCollection<int> inputQueue = new BlockingCollection<int>(); 
     BlockingCollection<int> outputQueue = new BlockingCollection<int>(); 
    } 
} 

PLINQ 및 데이터 흐름

You should also look into Plinq, 그리고 - 당신은 닷넷 4.5을 사용할 수 있는지 - 또한 Dataflow (Task Parallel Library)

1

는 .NET을 사용하는 경우는 4.0 당신은을 사용할 수 있습니다 Parallel.For 메소드. 루프를 병렬 처리하는 데 필요한만큼의 스레드를 실행합니다. 좋은 점은 스레드를 관리하고 스레드를 모니터링한다는 것입니다. 다음은 병렬에 대한 소개입니다. http://msdn.microsoft.com/en-us/library/dd460713.aspx

또한 작업 병렬 라이브러리가 .NET 4.0에서 도입 한 다른 구성을 조사해야합니다. 그것은 정말로 자신의 스레드를 시작하고 관리하는 것보다 멀티 스레딩을 훨씬 쉽게 해주는 정말 멋진 멀티 스레딩 헬퍼가 많이 있습니다. 여기에서 MSDN 문서를 볼 수 있습니다. http://msdn.microsoft.com/en-us/library/dd537609.aspx