2014-01-21 3 views
1

어제 나는 비동기/대기없이 여러 비동기 http 요청을 만드는 방법을 found out했습니다. 그러나 오늘 나는 그것을 반복 할 필요가있다 : 어떤 응답이 어떤 조건을 만족시키지 못한다면 - 나는 그들에 대한 요청을 변경하고이 요청을 다시 보낼 필요가있다. 그것은 여러 번 반복 될 수 있습니다.루프에서 비동기 http 요청을 만드는 방법은 무엇입니까?

do 
{ 
    var loadingCoordinatesTasks = new List<Task<Terminal>>(); 
    var totalCountOfTerminals = terminalPresetNode.ChildNodes.Count; 
    var uiTaskScheduler = TaskScheduler.FromCurrentSynchronizationContext(); 

    foreach (var terminal in terminals.Except(_terminalsWithCoordinates)) 
    { 
     var address = terminal.GetNextAddress(); 
     var webRequest = (HttpWebRequest)WebRequest.Create(GeoCoder.GeoCodeUrl + address); 
     var webRequestTask = Task.Factory.FromAsync<WebResponse>(webRequest.BeginGetResponse, 
                   webRequest.EndGetResponse, 
                   terminal); 
     var parsingTask = webRequestTask.ContinueWith(antecedent => 
     { 
      // Parse the response 
     }); 
     loadingCoordinatesTasks.Add(parsingTask); 
    } 

    Task.Factory.ContinueWhenAll(loadingCoordinatesTasks.ToArray(), antecedents => 
    { 
     foreach (var antecedent in antecedents) 
     { 
      var terminalWithCoordinates = antecedent.Result; 
      if (antecedent.Status == TaskStatus.RanToCompletion && 
       !terminalWithCoordinates.Coordinates.AreUnknown) 
      { 
       _terminalsWithCoordinates.Add(terminalWithCoordinates); 
       _countOfProcessedTerminals++; 
      } 
     } 
    }); 
} while (_countOfProcessedTerminals < totalCountOfTerminals); 

하지만이 가능가 후 요청 매 세트의 실행을 단지 while의 상태를 확인하기 : 이 코드를 시도했습니다?

답변

0

나는 재귀를 사용하여 수행 할 관리 :

public void RunAgainFailedTasks(IEnumerable<Task<Terminal>> tasks) 
    { 
     Task.Factory.ContinueWhenAll(tasks.ToArray(), antecedents => 
     { 
      var failedTasks = new List<Task<Terminal>>(); 
      foreach (var antecedent in antecedents) 
      { 
       var terminal = antecedent.Result; 
       // Previous request was failed 
       if (terminal.Coordinates.AreUnknown) 
       { 
        string address; 
        try 
        { 
         address = terminal.GetNextAddress(); 
        } 
        catch (FormatException) // No versions more 
        { 
         continue; 
        } 
        var getCoordinatesTask = CreateGetCoordinatesTask(terminal, address); 
        failedTasks.Add(getCoordinatesTask); 
       } 
       else 
       { 
        _terminalsWithCoordinates.Add(terminal); 
       } 
      } 
      if (failedTasks.Any()) 
      { 
       RunAgainFailedTasks(failedTasks); 
      } 
      else 
      { 
       // Display a map 
      } 
    }, CancellationToken.None, 
     TaskContinuationOptions.None, 
     TaskScheduler.FromCurrentSynchronizationContext()); 
} 

private Task<Terminal> CreateGetCoordinatesTask(Terminal terminal, string address) 
    { 
     var webRequest = (HttpWebRequest)WebRequest.Create(GeoCoder.GeoCodeUrl + address); 
     webRequest.KeepAlive = false; 
     webRequest.ProtocolVersion = HttpVersion.Version10; 
     var webRequestTask = Task.Factory.FromAsync<WebResponse>(webRequest.BeginGetResponse, 
                   webRequest.EndGetResponse, 
                   terminal); 
     var parsingTask = webRequestTask.ContinueWith(webReqTask => 
     { 
      // Parse the response 
     }); 
     return parsingTask; 
    } 
0

당신은 수를 늘린 후 검사를 수행 할 수 있습니다

_countOfProcessedTerminals++; 
if (_countOfProcessedTerminals >= totalCountOfTerminals) 
{ 
    break; 
} 

하지만 _countOfProcessedTerminals 스레드 안전합니까?

+0

감사합니다! 내 편집보기 – Zharro

+0

아니요, 아직 스레드로부터 안전하지는 않지만 할 수 있습니다. 문제는 루프를 구성하는 방법입니다. 'while (true) '라고 쓰면 여분의 요청이 많이 생성됩니다. – Zharro

관련 문제