2016-07-25 4 views
2

저는 매우 간단한 Raytracer를 작성하고 있습니다. 프로그램이 단일 스레드이기 때문에 런타임 제한이 있습니다. 내가 처리 한 2 ~ 3 가지 작업으로이 유형의 질문에 대한 답변을 Google을 통해 찾은 결과입니다.많은 양의 작업/스레드 생성 및 모두 완료하기를 기다리는 중

class Program 
{ 
    static void Main(string[] args) 
    { 
     var taskList = new List<Task>(); 

     taskList.Add(Task.Factory.StartNew(() => doStuff())); 
     taskList.Add(Task.Factory.StartNew(() => doStuff())); 
     taskList.Add(Task.Factory.StartNew(() => doStuff())); 

     Task.WaitAll(taskList); 

     Console.WriteLine("All threads complete"); 
    } 

    static void doStuff() 
    { 
     //do stuff here 
    } 
} 

순진하게 구현 된 경우 최소한 10,000 개의 개별 스레드가 있습니다. 위의 솔루션은이 시나리오에서 최적의 솔루션으로 보이지 않습니다. 표준 라이브러리에서 이것을 지원하는 부분이 있습니까? 아니면 구현 된 Nuget 패키지가 있습니까? 그것은 또한 바보 같은 짓일 수도 있습니다. List에있는 10,000 개 이상의 스레드는 전혀 문제가되지 않습니다. 그러면 문제는 컷오프가 될 때가됩니다. 어떤 경우에는 12500000 개의 작업/스레드가 필요 하겠지요. 나는 목록에 너무 많은 것을 확신합니다.

아래는 대략 새 스레드/작업을 작성하는 방법입니다. 당신은 당신이 여러 스레드를 사용하여 처리 할 값 목록 (또는 다른 IEnumerable<T>)가있는 경우

for (var x = 0; x < image.Width; x++) { 
    for (var y = 0; y < image.Height; y++) { 
     var coordinates = new Vector3(x, y, 0); 
     var task = new Task(() => { 
      RenderSinglePixel(coordinates); 
     }); 
    } 
} 
+2

의 전반적인 속도를 느리게한다. –

+0

그게 내가 생각한거야. 내 상황을 다루기위한 적절한 방법은 무엇입니까? – Herbstein

+0

예제를 추가해 보겠습니다. –

답변

2

, 당신은 그렇게 할 .AsParallel()를 사용할 수 있습니다.

이것은 프로세서 기능에 따라 동시에 생성되는 스레드 수를 지능적으로 제한합니다. 그러나 항목 당 작업량이 비교적 큰 경우에만이 값을 사용해야합니다. 여기

은 예입니다 :

using System; 
using System.Linq; 
using System.Threading; 

namespace Demo 
{ 
    class Program 
    { 
     static void Main() 
     { 
      var numbersToProcess = Enumerable.Range(1, 1000); 

      numbersToProcess.AsParallel().ForAll(doStuff); 
     } 

     static void doStuff(int value) 
     { 
      Console.WriteLine("Thread {0} is processing {1}", Thread.CurrentThread.ManagedThreadId, value); 
      Thread.Sleep(250); // Simulate compute-bound task. 
     } 
    } 
} 

또 다른 방법은 각 메서드 호출에 대한 작업을 만드는 것입니다, 그러나 대기하기 위해이 작업을 저장하지 않는 한 모든 스레드가 완료 될 때 알고 더 어려워진다 그들 완료 (그러나 스레드 풀 사용 스레드의 수가 너무 크게하지 않도록한다) :

using System; 
using System.Linq; 
using System.Threading; 
using System.Threading.Tasks; 

namespace Demo 
{ 
    class Program 
    { 
     static void Main() 
     { 
      var numbersToProcess = Enumerable.Range(1, 1000); 

      foreach (int number in numbersToProcess) 
      { 
       int n = number; 
       Task.Run(() => doStuff(n)); 
      } 

      Console.ReadLine(); 
     } 

     static void doStuff(int value) 
     { 
      Console.WriteLine("Thread {0} is processing {1}", Thread.CurrentThread.ManagedThreadId, value); 
      Thread.Sleep(250); // Simulate compute-bound task. 
     } 
    } 
} 

참고를이 방식은 스레드의 폭주 수의 위험을 실행 않습니다 생성되고, 난 f가 doStuff()으로 전화 할 때마다 매우 오랜 시간이 걸립니다. Thread.Sleep(250)Thread.Sleep(100000)으로 변경하고 프로그램을 실행하면 많은 수의 스레드가 만들어집니다.

하지만 가장 좋은 방법은 the DataFlow TPL입니다.

+0

처리해야하는 좌표 배열을 만들 수 있다고 생각합니다. 그러나 이것은 비효율적으로 보입니다. 이 작업을 수행하는 ThreadPool과 같은 메소드가 있습니까? – Herbstein

+0

@Herbstein 제 2의 예와 같이'Tasks'를 사용할 수 있습니다. 그러나 제가 지적했듯이, 마지막 작업이 언제 완료되었는지는 더 어색합니다. 그러나 아마도 DataFlow TPL을 살펴보고 싶을 것입니다. 큰 학습 곡선이 있지만 원하는 것에 가장 적합 할 것 같습니다. –

+0

도움을 주셔서 감사합니다! 아마도 'Task' 전용 버전을 구현 한 다음, 조금 더 시간이 지날 때 DataFlow TPL을 살펴볼 것입니다. 다시 한번 감사드립니다. – Herbstein

1

작은 몸체 패턴에는 병렬 루프를 사용하십시오. https://msdn.microsoft.com/en-us/library/dd560853(v=vs.110).aspx

Parallel.For 루프가 작은 본체를 가지고 는, 이러한 비주얼 베이직 루프를 들어 C에서 # for 루프와 같은 등가 시퀀셜 반복보다 느리게 수행 것이다. 느린 성능은 데이터를 분할하는 데 소요되는 오버 헤드와 각 루프 반복에서 대리인을 호출하는 비용 때문에 발생합니다. 이러한 시나리오를 해결하기 위해 Partitioner 클래스는 Partitioner.Create 메서드를 제공합니다.이 메서드를 사용하면 대리자 본문에 순차 루프를 제공 할 수 있으므로 반복 당 한 번만 수행되는 대신 파티션 당 한 번만 대리자가 호출됩니다.

작은 몸체 패러랠 패턴은 본질적으로 열거 형을 분할하고 프로세서 수에 따라 여러 스레드에서 루프를 실행합니다. 각 스레드는 작업 할 고유 한 파티션 그룹을 갖습니다.

이 패턴은 필요한 경우보다 많은 스레드를 생성하는 오버 헤드를 피하기 때문에이 시나리오에서는 일반적인 병렬 루프보다 성능이 좋습니다. CPU 코어보다

사용 스레드보다 단지 계산 바인딩 작업 프로세서 코어 이상의 스레드를 갖는 불량, 프로세싱 일반적

+1

이것이 스레드와 어떻게 관련되어 있는지 설명하십시오. –

+0

링크 만 대답하면 싫어합니다. 링크가 죽으면 대답은 더 이상 가치가 없습니다. 답안의 링크에서 관련 정보를 견적 블록에 포함하십시오. – Phaeze

+0

@Devlin 소체 패턴 용 병렬 루프 패턴은 필수적으로 열거 형을 분할하고 프로세서 수에 따라 루프를 여러 스레드로 실행합니다. 각 스레드는 작업 할 자체 파티션 그룹을 갖습니다. –

관련 문제