2012-05-26 5 views
1

여러 비동기 http 요청을 기다리는 방법에 대해 질문하고 싶습니다.여러 비동기 http 요청을 기다리는 방법

내 코드는 다음과 같다 :

public void Convert(XDocument input, out XDocument output) 
    { 
     var ns = input.Root.Name.Namespace; 

     foreach (var element in input.Root.Descendants(ns + "a")) 
     { 
      Uri uri = new Uri((string)element.Attribute("href")); 

      var wc = new WebClient(); 
      wc.OpenReadCompleted += ((sender, e) => 
      { 
       element.Attribute("href").Value = e.Result.ToString(); 
      } 
      ); 
      wc.OpenReadAsync(uri); 
     } 

     //I'd like to wait here until above async requests are all completed. 
     output = input; 
    } 

용량의 사람이 이것에 대한 해결책을 알아?

답변

2

그가 비 차단 요청을 수행하는 방법에 대해 설명하는에 article by Scott Hanselman 있습니다. 끝까지 스크롤하면 public Task<bool> ValidateUrlAsync(string url) 메서드가 있습니다.

당신은 (응답 독서에 대한보다 강력한 될 수 있음)

public Task<string> GetAsync(string url) 
{ 
    var tcs = new TaskCompletionSource<string>(); 
    var request = (HttpWebRequest)WebRequest.Create(url); 
    try 
    { 
     request.BeginGetResponse(iar => 
     { 
      HttpWebResponse response = null; 
      try 
      { 
       response = (HttpWebResponse)request.EndGetResponse(iar); 
       using(var reader = new StreamReader(response.GetResponseStream())) 
       { 
        tcs.SetResult(reader.ReadToEnd()); 
       }      
      } 
      catch(Exception exc) { tcs.SetException(exc); } 
      finally { if (response != null) response.Close(); } 
     }, null); 
    } 
    catch(Exception exc) { tcs.SetException(exc); } 
    return tsc.Task; 
} 

그래서 손이, 당신이 다음이 당신을두고이

var urls=new[]{"url1","url2"}; 
var tasks = urls.Select(GetAsync).ToArray(); 
var completed = Task.Factory.ContinueWhenAll(tasks, 
        completedTasks =>{ 
              foreach(var result in completedTasks.Select(t=>t.Result)) 
              { 
               Console.WriteLine(result); 
              } 
             }); 
completed.Wait(); 
//anything that follows gets executed after all urls have finished downloading 

희망처럼 사용할 수 있습니다 다음과 같이 수정할 수 있습니다 올바른 방향으로

추신. 이것은 async/await를 사용하지 않고 얻을 수있는 것만 큼 분명합니다.

1

continuation passing style을 사용해보십시오. 이처럼 변환 방법,

public void ConvertAndContinueWith(XDocument input, Action<XDocument> continueWith) 
{ 
    var ns = input.Root.Name.Namespace; 
    var elements = input.Root.Descendants(ns + "a"); 
    int incompleteCount = input.Root.Descendants(ns + "a").Count; 
    foreach (var element in elements) 
    { 
     Uri uri = new Uri((string)element.Attribute("href")); 

     var wc = new WebClient(); 
     wc.OpenReadCompleted += ((sender, e) => 
     { 
      element.Attribute("href").Value = e.Result.ToString(); 
      if (interlocked.Decrement(ref incompleteCount) == 0) 
       // This is the final callback, so we can continue executing. 
       continueWith(input); 
     } 
     ); 
     wc.OpenReadAsync(uri); 
    } 
} 

을 재구성 할 수 있다면 당신은 다음과 같이 그 코드를 실행 :

XDocument doc = something; 
ConvertAndContinueWith(doc, (finishedDocument) => { 
    // send the completed document to the web client, or whatever you need to do 
}); 
관련 문제