2016-07-06 4 views
2

이 포럼과 다른 사람들의 C# 멀티 스레드에 대한 많은 게시물을 검토 한 후에도 여전히 혼란스럽고 문제를 처리하는 데 어려움이 있습니다.스레드를 기다리는 C# 멀티 스레드 문제

각 정수의 함수를 실행하는 numThreads 개의 스레드 수를 documentIds에 만들고 싶습니다. documentIds은 Count = 100 인 List<int>이며 documentIds에있는 각 요소의 RestitchWorker.Restitch를 호출하려고합니다.

내가 현재 아래에 있지만 나는 5 개의 스레드를 계속 유지하고 100 개의 documentIds 목록을 통해 순환하는 방법에 대해 혼란 스럽다 ... 모든 도움을 받으실 수 있습니다.

for (int i = 0; i < documentIds.Count; i++) 
{ 
    if (threadCount < numThreads) 
    { 
     var Worker = new RestitchWorker(documentIds.ElementAt(i)); 
     Thread t_restitchWorker = new Thread(() => Worker.Restitch()); 
     threadCount++; 
     t_restitchWorker.Start(); 
     t_restitchWorker.Join(); 
    } 
} 
+0

. 조인? 어떤 종류의 게시물을 읽고 있었습니까? (귀하의 연구 결과에 대한 링크를 추가하면 정확히 무엇이 도움이되는지 이해하는 데 도움이됩니다.) –

+3

Parallel.ForEach (documentIds, new ParallelOptions {MaxDegreeOfParallelism = 5}, processDocumentId); – stuartd

답변

5

이 문제는 Threads가 아닌 Tasks에 더 적합합니다. 스레드를 명시 적으로 만드는 문제가 필요하지 않은 경우 쓰래드 풀이 비쌀 수 있다는 사실 때문에 쓰레드 풀링이 더 효율적일 수있다.

작업은 100 개의 긴 작업을 병렬로 느슨하게 수행해야하는 문제를 해결합니다. 100 개의 명시 적 스레드를 생성하는 대신 스레드를 풀링하고 여러 작업을 대기하는 API를 사용하기 쉽기 때문입니다. 작업의

목록

당신은 작업의 목록을 작성하고 System.Threading.Tasks.Task.WaitAll를 호출하여이 작업을 수행 할 수 있습니다 :

var tasks = new List<Task>(); 

for (int i = 0; i < n; ++i) 
{ 
    tasks.Add(Task.Run(action: SomeLongTask)); 
} 

Task.WaitAll(tasks); 

Parallel.For 그러나

을이 작업을 수행 할 수있는 더 좋은 방법 for 루프이므로 정수를 전달해야합니다. System.Threading.Tasks.Parallel.For :

Parallel.For(0, n, (i) => 
{ 
    SomeLongTask(i); 
}); 
2

응용 프로그램을 멀티 스레딩하기위한 메커니즘이 많이 있습니다. 비동기 작업, TPL (Task Parallel Library), 스레드 풀, 세마포어 등을 사용할 수 있습니다. 한 번에 생성 할 수있는 스레드 수에 대한 높은 수준의 제어가 필요할 때 사용하는 메커니즘은 세마포어를 사용하는 것입니다. 최대 스레드 수를 확인한 다음 Wait을 사용하여 새 스레드가 사용 가능할 때까지 기다립니다. 내 데이터 (예 : 문서 ID 목록)를 ConcurrentQueue에 넣으면 스레드 안전성에 대해 걱정할 필요없이 내 스레드가 작업을 수행하는 데 필요한 정보를 안전하게 대기열에 넣고 큐에서 빼낼 수 있습니다. 비동기 작업을 사용하여 실제로 작업을 시작할 수 있습니다.

static class Program 
{ 
    private const int _maxWorkers = 10; 
    private static readonly SemaphoreSlim _threadManager = new SemaphoreSlim(_maxWorkers); 

    private void DoStuff() 
    { 
     var queue = new ConcurrentQueue<int>(SomeClass.GetDocumentIds()); 
     var operations = new List<Task>(); 

     while (!queue.IsEmpty) 
     { 
      int documentId; 

      if (queue.TryDequeue(out documentId)) 
      { 
       _threadManager.Wait(); // this will block after max number of threads is met 
       try 
       { 
        operations.Add(GetDocument(documentId); 
       } 
       catch (Exception) 
       { 
        // ignored 
       } 
      } 
     } 

     Task.WaitAll(operations.ToArray()); // finally, this waits till the last remaining tasks are complete 
    } 

    private static async Task GetDocument(int documentId) 
    { 
     await Task.Yield(); 

      try 
      { 
       GoGetDocument(documentId); 
      } 
      catch (Exception) 
      { 
       // ignored 
      } 
      finally 
      { 
       _threadManager.Release(); // release the semaphore when the task completes 
      } 

    } 
+0

DoStuff가 여기 또는 어디에서 호출되는지 어떻게 보입니까? – GregH

+0

DoGetDocument의 출처 또는 수행해야하는 작업에 대해 잘 모름 ... 예제에 누락 된 코드가 있습니까? – GregH

+0

또한 GetDocument() 메서드는 메서드 서명을보고 작업을 반환해야하지만 메서드에서 아무 것도 반환하지 않습니다 ... – GregH