2014-02-09 3 views
1

MSMQ에서 메시지를 읽고 하나씩 처리하는 Windows 서비스가 있습니다. 성능/처리량을 향상시키기 위해 TPL로 이전했습니다. 메시지를 처리하는 동안 데이터베이스 호출과 WCF 호출이 있습니다. 우리는 WCF 호출을하는 동안 첫 번째 호출은 더 빠르지 만 후속 호출은 더 오랜 시간이 걸리는 것을 관찰했습니다. 다음은 샘플 코드입니다.비동기 WCF 호출에 더 많은 시간이 소요됩니다. 동기화 호출

public class TestWcf 
{ 
    public void Process(string option) 
    { 
     // container for perellel tasks and WaitAll after 50 count 
     TaskContainer batch = new TaskContainer(50, true); 

     for (int i = 1; i <= 100; i++) 
     { 
      if(option.Equals("s")) 
      { 
       batch.Add(ProcessMessage); 
      } 
      else 
      { 
       batch.Add(ProcessMessageAsync); 
      } 
     } 
    } 

    public void ProcessMessage() 
    { 
     Stopwatch sw = Stopwatch.StartNew(); 

     PostingServiceClient client = new PostingServiceClient(); 
     client.UpdateArchiveStatus(Guid.Parse("B6D5C77C-330A-4B00-96BF-E91A2B5970E3"),"1234567890"); 

     sw.Stop(); 
     Console.WriteLine("Thread {0}, Elapsed Time: {1} s", Thread.CurrentThread.ManagedThreadId, sw.Elapsed.Seconds); 
     //client.Close(); 
    } 

    public void ProcessMessageAsync() 
    { 
     Stopwatch sw = Stopwatch.StartNew(); 

     PostingServiceClient client = new PostingServiceClient(); 
     var task = Task.Factory.FromAsync(
      client.BeginUpdateArchiveStatus(Guid.Parse("B6D5C77C-330A-4B00-96BF-E91A2B5970E3"), "1234567890", null, 
       null), client.EndUpdateArchiveStatus); 
     task.Wait(); 

     sw.Stop(); 
     Console.WriteLine("Thread {0}, Elapsed Time: {1} s", Thread.CurrentThread.ManagedThreadId, sw.Elapsed.Seconds); 
     //client.Close(); 
    } 

} 

우리는 외부 팀 WCF를 사용하고 있으며 IIS 서버, App Pool targeting .Net 2.0에서 호스팅됩니다. WCF 서비스 측면에서 serviceThrottling은 500이며 서비스 계약에 정의 된 ServiceBehavior 특성이 없습니다. Sync 옵션이있는 콘솔 인스턴스 2 개와 비동기 옵션이있는 콘솔 인스턴스 2 개로 동일한 시간에 프로그램을 실행했습니다. 동기화 옵션은 비동기 옵션보다 훨씬 빠르게 완료되었습니다. 내 가정, 시스템 비동기 작업을 수행하는 동안 ThreadPool에서 작업을 공개하지 않습니다. 문제는 어떤 접근 방식이 더 좋고 (Sync vs. Async WCF 호출) 아니면이 시나리오에서 WCF 호출을 처리 할 수있는 다른 접근 방식이 있는지입니다.

+0

WCF 서비스 측의'UpdateArchiveStatus' 내부에서 어떤 일이 벌어지고 있습니까? – Noseratio

+0

SharePoint API를 사용하여 SharePoint 목록을 업데이트합니다. – brijshah

답변

0

아무 것도 알아보기 전에 Windows 서비스에 어떤 프레임 워크를 사용하고 있습니까? .Net 4.5 (또는 그 이상) 또는 .Net 4.0?

내가 물어 보는 이유는 async/await (.Net 4.5.)이 필요하다면 코드의 단순함이 크게 바뀔 수 있기 때문입니다.

이제 비즈니스에 대해 알아 보겠습니다. 그래서 당신이하는 일에 약간의 모순이 있습니다.

도대체 무엇입니까 TaskContainer 무엇입니까? 그것에 관한 문서를 찾을 수 없습니다.

이 코드 블록

var task = Task.Factory.FromAsync(
      client.BeginUpdateArchiveStatus(Guid.Parse("B6D5C77C-330A- 4B00-96BF-E91A2B5970E3"),"1234567890", null, null), 
      client.EndUpdateArchiveStatus); 

task.Wait(); 

하지 비동기입니다.

task.Wait() 호출로 인해 작업을 사용하는 것이 동기입니다. Task을 사용하는 데 일정한 오버 헤드가 발생할 수 있지만 대부분의 경우 비동기 및 확장 성의 이점이이 작은 오버 헤드보다 중요합니다. 이 작은 오버 헤드는 차단 호출을하거나 스레드를 차단하여 네트워크 호출을 수행하는 것보다 낫습니다. 하는 동안 시스템은 ThreadPool이에서 작업을 방출하지 않는,

내 가정 : 당신의 가정을 해결하기 위해

var guid = Guid.Parse("B6D5C77C-330A-4B00-96BF-E91A2B5970E3"); 

// Since I don't have a copy of the operation contract, 
// I can't tell if the client call returns a specific type, 
// so I'm going to assume it's `void` 
var task = Task.Factory.FromAsync(client.BeginUpdateArchiveStatus, client.EndUpdateArchiveStatus, guid, null); 

// If you're using .Net 4.5 or higher 
// Another side note is that you'll want to return `async Task` instead of `async void` if you decide/can use `await` 
await task; 
sw.Stop(); 

// If you're not using .Net 4.0 
task.ContinueWith(t => 
    { 
    sw.Stop(); 
    // Whatever code you want to execute now. 
    }); 

: 당신이 진정한 비동기 호출을 원하는 경우

, 당신은 이런 식으로 뭔가를해야 할 것 비동기 조작.

Task.Factory.FromAsync을 스레드 풀 스레드를 차단되지 않습니다 진정 비동기 호출에 사용. (이 자원의 톤이를 확인하기 위해,하지만 here's 내가 빨리 뽑아입니다.)

질문입니다, 더 나은하는 방법 (동기화 비동기 WCF 호출 대) 또는 처리 할 수있는 다른 방법이있다 이 시나리오에서 WCF 호출.

가장 좋은 방법은 비동기 작업을 올바르게 구현하는 것입니다.


[1] : 당신은 VS 2012 이상이있는 경우, NuGet 패키지 Microsoft.Bcl.Async에서 끌어와 닷넷 4.0이 문제를 해결 얻을 수 있습니다.

편집 : 방금 1 년 이상 된 질문에 부딪쳤다. 죄송합니다. 그게 답이없는 질문을 줄이기 위해 얻은 것입니다.

관련 문제