2012-04-09 4 views
16

은 정말 최대 잠재력을 TplDataflow를 사용하지 않는 ... http://social.msdn.microsoft.com/Forums/en-US/tpldataflow/thread/89b3f71d-3777-4fad-9c11-50d8dc81a4a9명백한 BufferBlock.Post/Receive/ReceiveAsync 인종/버그

내가 알고 교차 기록했다. ATM 단순히 메시지 전달을위한 안전한 대기열로 BufferBlock을 사용하고 있습니다. 여기서 생산자와 소비자는 다른 속도로 실행됩니다. 하는 방법에 관해서는 저를 곤란하게 만드는 이상한 행동을보고 있습니다. (2000 라인 분산 솔루션의 일부입니다) 위의 코드에서

private BufferBlock<object> messageQueue = new BufferBlock<object>(); 

public void Send(object message) 
{ 
    var accepted=messageQueue.Post(message); 
    logger.Info("Send message was called qlen = {0} accepted={1}", 
    messageQueue.Count,accepted); 
} 

public async Task<object> GetMessageAsync() 
{ 
    try 
    { 
     var m = await messageQueue.ReceiveAsync(TimeSpan.FromSeconds(30)); 
     //despite messageQueue.Count>0 next line 
     //occasionally does not execute 
     logger.Info("message received"); 
     //....... 
    } 
    catch(TimeoutException) 
    { 
     //do something 
    } 
} 

Send 주기적으로 100ms마다 정도라고되고있다. 즉, 항목은 Post이고 messageQueue은 초당 약 10 회입니다. 확인되었습니다. 그러나 때때로 ReceiveAsync이 시간 초과 (즉 PostReceiveAsync을 완료하지 못함)를 완료하지 못하고 30 초 후에 TimeoutException이 발생하는 경우가 있습니다. 이 시점에서 messageQueue.Count은 수백입니다. 예상치 못한 결과입니다. 이 문제는 게시 속도가 느린 경우 (1 초당 1 회) 관찰되었으며 일반적으로 1000 개 항목이 BufferBlock을 통과하기 전에 발생합니다.

그래서이 문제를 해결, 내가 일 다음과 같은 코드를 사용하고 작동,하지만

public async Task<object> GetMessageAsync() 
    { 
     try 
     { 
      object m; 
      var attempts = 0; 
      for (; ;) 
      { 
       try 
       { 
        m = await messageQueue.ReceiveAsync(TimeSpan.FromSeconds(1)); 
       } 
       catch (TimeoutException) 
       { 
        attempts++; 
        if (attempts >= 30) throw; 
        continue; 
       } 
       break; 

      } 

      logger.Info("message received"); 
      //....... 
     } 
     catch(TimeoutException) 
     { 
      //do something 
     } 
    } 

이 경쟁 조건처럼 보이는 (로 인해 발생하는 위의 버그) 수신 할 때 가끔 1 초 지연이 발생 TDF에서 나에게,하지만 내가 왜 BufferBlock 유사한 방식으로 사용하는 다른 장소에서 발생하지 않습니다의 바닥에 도착할 수 없습니다. 실험적으로 ReceiveAsync에서 Receive으로 변경하는 것은 도움이되지 않습니다. 나는 체크하지 않았지만 위와 같은 코드가 완벽하게 작동한다는 것을 별도로 상상한다. 그것은 "TPL 데이터 흐름 소개"tpldataflow.docx에 문서화 된 패턴입니다.

내가이 일을 처리하기 위해 무엇을 할 수 있습니까? 무슨 일이 일어나는지 추측하는 데 도움이되는 통계가 있습니까? 신뢰할 수있는 테스트 케이스를 만들 수 없다면 어떤 정보를 더 제공 할 수 있습니까?

도움말!

+1

내가하고있는 일이나 기대하는 바가 잘못된 것은 아닙니다. 나는 확실히 당신이 MSDN 포럼에서 여기보다 더 적극적으로 유지할 필요가 있다고 생각합니다. 당신은 이미 @StephenToub의 주목을 받았고, 그는 당신이 그것을보고 싶어하는 사람입니다. –

+0

아니요. 결코 그것의 바닥에 도착했다. 나는 작은, 독립적 인 예제에서 문제를 재현 할 수 없었다. BufferBlock 만 사용하고 있기 때문에 대신 자체 비동기 대기열 구현을 사용했습니다. 다른 코드를 변경할 필요가 없었습니다 ... 단순히 사용중인 BufferBlock 인터페이스 부분을 다시 구현했습니다. 이제는 대접을 받아야합니다. 그것은 저에게 뭔가 잘못되었다고 생각하게 만듭니다. 그러나 나는 그것을 증명할 수 없습니다. Grr. – spender

+0

@spendor 매우 흥미 롭습니다, 이상하게도 BufferBlock을 찾은 후에 자체 비동기 동시 대기열 구현을 스크랩했습니다 ...이제 다시 생각해야 할 것입니다. 감사. –

답변

1

스티븐은 다음의 해결책이라고 생각하는 것 같다

var에 m = messageQueue.ReceiveAsync()을 기다리고 있습니다;

대신 :

VAR의 m = 기다리고 messageQueue.ReceiveAsync (TimeSpan.FromSeconds (30));

당신이 이것을 확인 또는 부인할 수 있습니까?

+0

그게 효과가 없었어요. ReceiveAsync 과부하가 어떤 문제인지는 중요하지 않습니다. 그 결과는 같습니다. 내 의견을 위의 내 의견을 참조하십시오. – spender

관련 문제