繁体   English   中英

如何等待多个异步http请求

[英]How to wait for multiple async http request

我想问一下如何等待多个异步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;  
    }

任何人都知道这个解决方案吗?

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

希望这能让你朝着正确的方向前进。

PS。 这可能很明显,因为它可以在不使用async / await的情况下获得

考虑使用延续传递样式 如果你可以像这样重构你的Convert方法,

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
});

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM