1

.NET 4.0 Parallel Extensions을 사용하여 장기 실행 프로세스의 결과를 순차적으로 처리하는 우선 순위가 낮은 스레드에서 처리하는 가장 좋은 방법을 알고 싶습니다.병렬 확장을 사용하여 우선 순위가 낮은 스레드에서 대기중인 항목을 순차적으로 처리하는 방법

I이 모두 실행을 수행하고 결과를 제공하는 다음과 같은 클래스 :

public class Step 
{ 
    public string Name { get; set; } 
    public TimeSpan Duration { get; set; } 
    public bool Completed { get; set; } 

    public void Execute() 
    { 
    DateTime before = DateTime.Now; 
    RemotedService.DoSomeStuff(); 
    Duration = DateTime.Now - before; 
    Completed = true; 
    } 
} 

가 어떻게 다음 단계를 처리하고 또한 처리 후, 순서 파일로 저장할 수 있습니까? RemotedService.DoSomeStuff()이 서버의 응답을 기다리는 동안 파일에 저장하고 싶습니다.

파일을 작성하는 것은 같은 것하십시오 Queue에 추가하고이를 처리하는 Timer을하는 것입니다 마음에 오는

using (StreamWriter w = File.AppendText("myFile.txt")) 
{ 
    var completedStep = completedSteps.Dequeue(); 
    w.WriteLine(string.Format("Completed {0} with result: {1} and duration {2}", 
          completedStep.Name, 
          completedStep.Completed, 
          completedStep.Duration)); 
} 

하나의 옵션. 그러나 이것은 원격 호출의 다운 타임을 이용하지 않습니다.

또 다른 옵션은 Step에 대해 System.Threading.Tasks.Task을 사용하여 비동기식으로 각 결과를 파일에 쓰는 것입니다. 그렇다고해서 순서대로 저장되지 않을 수도 있으며 파일에 쓰는 것과 관련하여 경합이 발생할 수도 있습니다.

답변

1

BlockingCollection<Step> (System.Collections.Concurrent 네임 스페이스 참조)을 만드는 것이 좋습니다. 각 단계가 완료되면 해당 단계가 해당 컬렉션에 추가됩니다. BlockingCollection의 기본 동작은 대기열로 작동하므로 원하는 FIFO 동작을 얻을 수 있습니다.

두 번째 스레드가 큐를 서비스하여 각 항목을 제거하고 로그 파일에 기록합니다. 대기열을 추가 한 경우

그래서 :

static private BlockingCollection<Step> LogQueue = new BlockingCollection<Step>(); 
는 항목이 완료된 후에 당신은 당신의 Execute 방법이를 추가

:

LogQueue.Add(this); 

그리고 당신의 로그 스레드, 당신은 시작할 것이다 정적 생성자 :

static void LoggingThread() 
{ 
    using (var w = new StreamWriter(...)) 
    { 
     while (!LogQueue.IsCompleted()) 
     { 
      Step item; 
      if (LogQueue.TryTake(out item)) 
      { 
       w.WriteLine(....); 
      } 
     } 
    } 
} 

내가 작성한 로깅 스레드 System.Threading 스레드를 사용합니다. TPL을 사용하면 더 쉽고 더 좋은 방법이 될 수 있습니다. 나는 TPL에 대해 몹시 익숙하지 않았기 때문에 말할 수 없었다.

+0

스레딩에 대한 나의 무지를 용서하십시오.하지만 대기열이 비어있을 때 백그라운드 스레드가 불필요하게 while 루프를 처리하므로 실제로 작업을 수행하는 동안 활성 테드가 느려지므로 걱정할 것입니다. 그렇지 않은가요? –

+0

즉, 백그라운드 스레드에서 LogQueue.IsCompleted()가 계속해서 호출됩니다.나는 이것을 피하기 위해 while 루프의 중간에 Thread.Sleep()을 보았지만, 나쁘다. –

+3

@Michael :'BlockingCollection'의 모든 대기는 비지 대기입니다. 그들은 사건에 의존합니다. 따라서 스레드가 대기열에서 대기 중이면 (즉, 'TryAdd' 또는'TryTake') 스레드는 유휴 상태입니다. CPU를 사용하지 않습니다. 따라서 특정한 경우에'LogQueue.IsCompleted()'는'false'를 반환하고,'TryTake'에 대한 호출은 즉시 항목을 반환하거나, 항목이 추가 될 때 트리거되는 이벤트를 기다립니다. 열. –

0

당신은 말 그대로 워크 플로 파운데이션의 사용 사례를 설명하고 - 그것은 않는이 물건을 모두 당신을 위해 :

+0

내 프로젝트에 종속성을 도입하는 것이 정당화 될 수 있는지 모르겠으므로 백그라운드에서 순차적으로 저장할 수 있습니다. 그래도 문제 영역이 WF와 얼마나 밀접하게 연관되어 있는지 생각하지 못했습니다. 나를 계몽 해 주셔서 감사합니다! –

1

한 가지 방법은 사용자 정의 작업 스케줄러 (http://msdn.microsoft.com/en-us/library/ee789351.aspx 참조) 작성하는 것입니다. 사용자 정의 작업 스케줄러는 동시성을 한 번에 한도로 제한하고 엄중 한 주문 실행을 시행 할 수 있습니다.

작업 스케줄러를 생성하면 스레드 우선 순위 또는 일부 상황에서 바람직 할 수도있는 ApartmentState를 제어 할 수 있습니다.

관련 문제