2012-05-20 3 views
2

현재 수천 개의 파일을 보유하고있는 대형 바이너리 파일을 읽는 응용 프로그램에서 모든 파일이 응용 프로그램의 다른 클래스에 의해 처리되고 있습니다. 이 클래스는 객체 또는 null을 반환합니다. 기본 양식에 진도를 보여주고 싶지만 어떤 이유에서든 내 머리를 감당할 수 없습니다.FromCurrentSynchronizationContext, 뭔가 빠졌습니까?

int TotalFound = 0; 
var uiScheduler = TaskScheduler.FromCurrentSynchronizationContext; 
BufferBlock<file> buffer = new BufferBlock<file>(); 
DataflowBlockOptions options = new DataflowBlockOptions(){ TaskScheduler = uiScheduler, }; 
var producer = new ActionBlock<someObject>(largeFile=>{ 
    var file = GetFileFromLargeFile(largeFile); 
    if(file !=null){ 
     TotalFound++; 
     buffer.post(file); 
     lblProgress.Text = String.Format("{0}", TotalFound); 
    } 
}, options); 

은 위의 코드는 심지어는 "TaskScheduler.FromCurrentSynchronizationContext"사용합니까, 내 양식을 정지, 왜? 나는 내 양식 아래의 코드를 사용할 때 잘 업데이트하기 때문에

DataflowBlockOptions options = new DataflowBlockOptions(){ TaskScheduler = uiScheduler, }; 
var producer = new ActionBlock<someObject>(largeFile=>{ 
    var file = GetFileFromLargeFile(largeFile); 
    if(file !=null){ 
     Task.Factory.StartNew(() => { 
      TotalFound++; 
      buffer.Post(file); 
     }).ContinueWith(uiTask => { 
      lblProgress.Text = String.Format("{0}", TotalFound); 
     },CancellationToken.None, TaskContinuationOptions.None, uiScheduler);   
    } 
}); 

나는이 모든 TPL 데이터 흐름에 새로운 오전, 그래서 나는 누군가가 두 번째 코드에서 작동 니펫을 이유에 첫 번째 조각에서 약간의 빛을 공유 할 수 바라고 그렇지 않습니다.

종류와 관련, 마티

답변

4

당신의 UI가 당신이 FromCurrentSynchronizationContext을 사용하고 becase이다 차단 이유. 코드가 UI 스레드에서 실행되도록합니다. 즉, 장기 실행중인 작업 (대부분 GetFileFromLargeFile())을 수행하면 코드가 고정됩니다.

반면에 UI 스레드에서 lblProgress.Text을 실행해야합니다.

이 코드에서 lblProgress.Text을 직접 설정해야할지 모르겠지만 너무 빡빡한 커플 링처럼 보입니다. 하지만 그렇게하려면, 당신은 UI 스레드에서 그냥 라인을 실행해야한다고 생각 :

var producer = new ActionBlock<someObject>(async largeFile => 
{ 
    var file = GetFileFromLargeFile(largeFile); 
    if (file != null) 
    { 
     TotalFound++; 
     await buffer.SendAsync(file); 
     await Task.Factory.StartNew(
      () => lblProgress.Text = String.Format("{0}", TotalFound), 
      CancellationToken.None, TaskCreationOptions.None, uiScheduler); 
    } 
}); 

을하지만 GetFileFromLargeFile() 비동기를 만들어이 어떤 장기를하지 않도록 한 경우에도 더 나은 솔루션이 될 것입니다 UI 스레드에서 실행중인 작업 (ConfigureAwait(false)이 도움이됩니다). 당신이 것을 한 경우, ActionBlock의 코드는 UI를 동결하지 않고 UI 스레드에서 실행할 수 있습니다 :

var producer = new ActionBlock<someObject>(async largeFile => 
{ 
    var file = await GetFileFromLargeFile(largeFile); 
    if (file != null) 
    { 
     TotalFound++; 
     await buffer.SendAsync(file); 
     lblProgress.Text = String.Format("{0}", TotalFound) 
    } 
}, options); 
+0

TNX는 설명 알려 분명합니다. 여전히 한 가지 질문이 있습니다. 첫 번째 예제에서와 같이 UI 스레드 외부에서 작업을 실행하는 것이 더 좋습니까? 응용 프로그램의 성능에 상관없이이 작업을 수행합니까? – Martijn

+0

작업이 매우 짧은 시간 동안 만 실행되는 경우 문제가되지 않습니다. 그렇지 않으면 UI 스레드에서 장기 실행 작업을 절대로 실행해서는 안됩니다. 성능 때문에가 아니라 응용 프로그램이 중단되기 때문입니다. – svick

+0

gui 업데이트를 처리하는 다른 (더 나은) 방법이 있습니까? 내가 추천 한 코드를 svick으로 적용했지만 여전히 내 UI가 얼어 버렸다. 내 응용 프로그램에는 총 8 개의 ActionBlock 이 있으며, 각 객체는 사용자 정의 객체에 대한 작업을 수행하며, 3 ActionBlocks는 MaxParallizism을 수행 할 때 프로세서 수를 설정한다. 7. 8 개의 ActionBlocks 모두 gui와 통신합니다 ... 그래서 이론적으로 gui를 업데이트하려는 30 개 이상의 작업이 될 수 있습니다. 누구든지 어떤 생각? – Martijn

관련 문제