2010-01-23 3 views
3

웹 요청을 비동기 적으로 실행하려고합니다. 한 가지만 제외하면 잘 작동하는 코드가 있습니다. BeginGetResponse에 제한 시간을 지정하는 기본 제공 방법이없는 것 같습니다. MSDN의 예제는 명확하게 동작하는 예제를 보여하지만 단점은 모두가 다시 한번 분명하게 블록을 스레드를 알리는스레드를 차단하지 않고 HttpWebRequest.BeginGetResponse에서 시간 초과 값을 지정하는 방법

SomeObject.WaitOne() 

로 끝날 것입니다. 로드가 많은 환경에서 차단할 수는 없지만 2 초 이상 걸리면 요청을 시간 초과해야합니다. 별도의 스레드 풀을 생성하고 관리하는 것의 단축은 프레임 워크에 이미 존재하는 것입니까?

시작 예 :

는 내가하고 싶은 것은 내 시간 제한 매개 변수가 일부 표시와 함께, 만료 된 후 호출 될 BeginGetResponse()에 비동기 콜백 수있는 방법입니다 시간 초과가 발생했습니다.

비동기 호출에서는 명백하게 TimeOut 매개 변수가 적용되지 않습니다. ReadWriteTimeout 매개 변수는 응답이 반환 될 때까지 재생되지 않습니다. 비 독점적 인 솔루션이 바람직합니다.

편집 : BeginGetResponse를 호출 한 후, 내 시간과 Timer를 작성하고 그 처리의 "시작"단계의 끝입니다 :

여기에 내가 무엇을 최대 온입니다. 이제 요청이 완료되고 "종료"단계가 호출되거나 제한 시간이 만료됩니다.

경주를 탐지하고 단 하나의 승자를 얻으려면 스레드로부터 안전한 방식으로 "완료된"카운터를 증가 시키십시오. "timeout"이 다시 돌아올 첫 번째 이벤트 인 경우 요청을 중단하고 타이머를 중지합니다. 이 상황에서 "end"가 호출되면 EndGetResponse은 오류를 발생시킵니다. "end"단계가 먼저 발생하면 카운터를 증가시키고 "timeout"은 요청을 중단합니다.

구성 가능한 시간 제한을 제공하면서 원하는 것처럼 작동하는 것 같습니다. 단점은 여분의 타이머 객체와 피할 노력을하지 않는 콜백입니다. 내가 1-3 스레드가 여러 부분을 처리 (시작, 시간 초과, 끝) 볼 그래서이 일하는 것 같습니다. 그리고 나는 어떤 "기다림"전화도 가지지 않는다.

너무 많은 수면을 놓치고 있거나 차단하지 않고 요청을 처리하는 방법을 찾았습니까? 당신이 할 수있는

int completed = 0; 

this.Request.BeginGetResponse(GotResponse, this.Request); 
this.timer = new Timer(Timedout, this, TimeOutDuration, Timeout.Infinite); 

private void Timedout(object state) 
{ 
    if (Interlocked.Increment(ref completed) == 1) 
    { 
     this.Request.Abort(); 
    } 
    this.timer.Change(Timeout.Infinite, Timeout.Infinite); 
    this.timer.Dispose(); 
} 

private void GotRecentSearches(IAsyncResult result) 
{ 
    Interlocked.Increment(ref completed); 
} 

답변

0

보인다 내 원래의 접근 방법이 가장 좋은 방법처럼 사용 가능.

+0

어떤 접근법을 택한 것입니까? 이 하나 또는 당신은 더 나은 접근 방식을 찾았나요? 당신은 어디에서든지 전체 소스를 가지고 있습니까? – mythz

0

그래서 여전히 메인 스레드가 살아, 분리 된 스레드로 HttpWebRequest을 실행하기 위해 BackgroundWorker를 사용합니다. 따라서 백그라운드 스레드는 차단되지만 첫 번째 스레드는 차단되지 않습니다.

이 문맥에서는 ManualResetEvent.WaitOne()과 같은 샘플을 사용할 수 있습니다 : HttpWebRequest.BeginGetResponse() 메서드.

+0

내 질문에 언급 된 WaitOne 블록. 비 차단 솔루션이 필요합니다. –

+0

예, 현재 스레드를 차단합니다. 그래서 BackgroundThread 내부에서 실행하는 것이 좋습니다. –

+0

그렇게하면 ThreadPool 스레드가 여전히 소모됩니다. 내 최근 편집을 참조하십시오. –

0

어떤 응용 프로그램입니까? 서비스 처리/웹 애플리케이션/콘솔 앱입니까?

작업로드 (요청)를 어떻게 작성하고 있습니까? 완료해야하는 작업 대기열이있는 경우 빌드 된 시간 초과에 대한 프레임 워크를 사용하여 'N'개의 비동기 요청을 시작한 다음 각 요청이 완료되면 (시간 초과 또는 성공으로) 큐에서 다음 요청을 가져올 수 있습니다.

이렇게하면 프로듀서/소비자 패턴이됩니다. 당신이 N "의 최대하도록 응용 프로그램을 구성하는 경우

그래서, 교대.

를 요청 사이에 당신이 (폐기하지 않고) 다시 N '타이머'뛰어난 요청을, 당신은 풀을 유지할 수 있습니다 '또는 당신이 당신의 타이머를 관리 할 수 ​​ThreadPool.SetTimerQueueTimer()를 사용할 수 있습니다. 스레드 풀은 당신을 위해 타이머를 관리하고 요청 사이의 타이머를 다시 사용합니다.

희망이 도움이됩니다.

+0

이것은 톱 10 웹 사이트이며 로직은 9K rps를 초과하는 속도로 모든 페이지에서 실행됩니다. 어디서나 차단하는 것은 옵션이 아닙니다. –

+0

올바르게 이해한다면 ASPX 페이지에서받은 각 요청에 대해 하나 이상의 (또는 그 이상) 비동기 HTTPWebRequests를 발행하고 있습니까? 그렇다면 ASPX에서 활용할 수있는 비동기 패턴이 있습니까? 만약 있다면, 비동기 웹 요청을 시작하여 완료로 페이지 완료를 트리거 할 수 있습니다. 시간이 초과되면 오류 코드 또는 다른 것을 사용하여 페이지 완료를 트리거 할 수도 있습니다. 그렇게하면 스레드 풀 스레드를 보유 할 수 없습니다. – feroze

0

당신이 비동기/기다릴 수 있다면

private async Task<WebResponse> getResponseAsync(HttpWebRequest request) 
     { 
      var responseTask = Task.Factory.FromAsync(request.BeginGetResponse, ar => (HttpWebResponse)request.EndGetResponse(ar), null); 
      var winner = await (Task.WhenAny(responseTask, Task.Delay(new TimeSpan(0, 0, 20)))); 
      if (winner != responseTask) 
      { 
       throw new TimeoutException(); 
      } 
      return await responseTask; 
     }