2014-09-15 3 views
2

MSDN의 예제를 따라 동시성을 제한하는 작업 스케줄러를 만들기위한 데모를 만들었습니다. maxDegreeOfParallelism가 2for 루프를 사용하여 동시성을 제한하는 작업 스케줄러를 만들기위한 작업 추가

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Threading; 
using System.Threading.Tasks; 

namespace TaskSchedulerThatLimitsConcurrency 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      // Create a scheduler that uses two threads. 
      LimitedConcurrencyLevelTaskScheduler lcts = new LimitedConcurrencyLevelTaskScheduler(2); 
      List<Task> tasks = new List<Task>(); 

      // Create a TaskFactory and pass it our custom scheduler. 
      TaskFactory factory = new TaskFactory(lcts); 
      CancellationTokenSource cts = new CancellationTokenSource(); 

      // Use our factory to run a set of tasks. 
      Object lockObj = new Object(); 
      for (int i = 0; i < 4; i++) 
      { 
       var myFactory = new TaskFactory(lcts); 
       Task t = myFactory.StartNew(() => 
       { 
        if (cts.IsCancellationRequested) 
         return; 
        lock (lockObj) 
        { 
         MakeTest(i, 1); 
        } 
       }, cts.Token); 
       tasks.Add(t); 
      } 
      for (int i = 0; i < 4; i++) 
      { 
       var myFactory = new TaskFactory(lcts); 
       Task t1 = myFactory.StartNew(() => 
       { 
        if (cts.IsCancellationRequested) 
         return; 
        lock (lockObj) 
        { 
         MakeTest(i, 2); 
        } 
       }, cts.Token); 
       tasks.Add(t1); 
      } 
      // Wait for the tasks to complete before displaying a completion message. 
      Task.WaitAll(tasks.ToArray()); 
      Console.WriteLine("\n\nSuccessful completion."); 
      Console.Read(); 
     } 

     private static void MakeTest(int i, int p) 
     { 
      StringBuilder sb = new StringBuilder(); 
      sb.Append(i.ToString() + "_" + p.ToString()); 
      Console.WriteLine(sb.ToString()); 
     } 
    } 
} 

로 설정된 결과

1

태스크 T1이고, T2는 거의 동일하다. 차이는 MakeTest(i, 1)MakeTest(i, 2)입니다. 나는 두 번째 for 루프를 사용하여 작업을 추가 할 수 있을까?

다음 코드를 사용했지만 분명히 결과가 잘못되었습니다.

for (int j = 0; j < 2; j++) 
     { 
      for (int i = 0; i < 4; i++) 
      { 
       var myFactory = new TaskFactory(lcts); 
       Task t1 = myFactory.StartNew(() => 
       { 
        if (cts.IsCancellationRequested) 
         return; 
        lock (lockObj) 
        { 
         MakeTest(i, j+1); 
        } 
       }, cts.Token); 
       tasks.Add(t1); 
      } 
     } 

결과 :

2

질문 :

  1. 내 원래의 코드는 출력 예 : "0_1", "1_1"등 올바른 결과를하지 않았다 왜?
  2. 수정 된 코드의 두 번째 루프에서 올바른 결과를 생성하는 방법은 무엇입니까? 내 실제 경우에는 최대 DegreeOfParallelism 큰 수입니다. MSDN example.으로 작업 목록에 하나씩 추가 할 수 없습니다 for 루프를 사용해야한다고 생각했습니다.
+0

당신에게 "한계"의 수를 필요로 어떤 시나리오 "maxDegreeOfParallelism가 큰 숫자는"이러한 변수는 루프 내에서 범위가 될 수 있기 때문에, 촬영 값은 해당 변수가 특정 반복하는 동안 한 무슨 값 남아있을 것입니다 동시 스레드 수를 크게합니다. 나는 전문가는 아니지만이 숫자가 기본 하드웨어/VM이 동시에 실행할 수있는 최대 스레드 수보다 높으면 확실하게 아무 것도하지 않을 것입니다. –

답변

2

StartNew에 전달하는 람다는 ij 변수에 클로저를 만듭니다. 그것은 폐쇄를 통해 그 변수가 아닌 년대 변수을이기 때문에, MakeTest() 오히려 전화 할 때의 가치보다, MakeTest()가 호출되는 시점에 ij의 가치를 전달됩니다 StartNew. 첫 번째 스레드가 코드의 해당 지점에 도달하기 전에 for 루프가 완료되었다고 가정하면 의 마지막 값은 i이고 jfor 루프를 통과 한 값입니다. http://ericlippert.com/2009/11/12/closing-over-the-loop-variable-considered-harmful-part-one/

간단한 수정이 for 루프 내부에 새로운 변수를 선언하는 것입니다 :

은 자세한 내용은 에릭 Lippert의의 문서를 참조하십시오.

for (int j = 0; j < 2; j++) 
{ 
    for (int i = 0; i < 4; i++) 
    { 
     var capturedI = i; 
     var capturedJ = j; 
     ... 
        MakeTest(capturedI, capturedJ+1); 
     ... 
+0

그래서 빨리 고치는 법? –

+0

@Love : 내 편집을 참조하십시오. – StriplingWarrior

관련 문제