我有一个网址列表。我运行OpenreadAsyn(url1)到OpenReadAsync(urlN)..如何等待所有这些完成

时间:2019-01-19 10:31:53

标签: c# multithreading rest webclient

我有一个长度为N的结果列表。 我有N个网址的网址列表。 我需要执行以下操作。

            List<Result> results=new List<Result>;
            //Urls is a list of URLs.

            public void FillResults()
            {
                 foreach( var urlx in Urls)
                 {
                        GetResponse(urlx, (response) =>
                        {
                            if (response != null && response.StatusCode==200)
                            {
                                Result result=new Result;
                                result.Value=response.SomeValue;
                                result.url=urlx;------>It is important that SomeValue corresponds to urlx and not other say,urly
                                results.Add(result);


                            }
                        });
                }
            }

             //wait till List results is completely filled

             private void GetResponse(Uri uri, Action<MyResponse> callback)
                    {
                        using(var m_webClient = new WebClient())
                        {
                        m_webClient.OpenReadCompleted += (o, a) =>
                        {
                            if (callback != null)
                            {
                                DataContractJsonSerializer ser = new DataContractJsonSerializer(MyResponse));
                                callback(ser.ReadObject(a.Result) MyResponse);

                            }
                        };
                        m_webClient.OpenReadAsync(uri);

                    }
                }

                public class MyResponse:Response
                {
                }

//等待结果列表完全填满

我希望每个请求都异步发生,但是要等到结果列表完全填满后再前进。

1 个答案:

答案 0 :(得分:0)

有两种解决方案。一种快速而又肮脏的方法是添加一个计数器,以告诉您剩余多少工作将像在调用GetResponse之前一样增加,并在回调中减少,如果达到0,则调用流程中的下一步。由于竞争条件和不可预测的线程行为(例如,如果您调用一个请求并且在第二个请求开始之前,然后尝试继续),这将具有风险。

更好的解决方案是跟踪使用OpenReadTaskAsync而不是OpenReadAsync然后使用Task.WhenAll({ALL YOUR TASKS})生成的任务。

它会稍微改变您的程序:

List<Result> result = new List<Result>();
List<Task<Stream>> jobs = new List<Task<Stream>>();

...

GetResponse必须返回一个简单的Task值。

private Task<Stream> GetResponse(Uri uri, Action<MyResponse> callback)
{
  ... //Almost all of your code stays the same, 
      //though you should close the stream you receive in the OnReadCompleted callback.
  return m_webClient.OpenReadTaskAsync(uri.ToString());
}

最后一种FillResults方法中,您必须将这些任务添加到列表中并等待。

public async Task FillResults()
{
      foreach( var urlx in Urls)
      {
            jobs.Add(
                      GetResponse(urlx, (response) =>
                      {
                        if (response != null && response.StatusCode==200)
                        {
                            Result result=new Result;
                            result.Value=response.SomeValue;
                            result.url=urlx;------>It is important that SomeValue corresponds to urlx and not other say,urly
                            results.Add(result);
                        }
                      })
                   );
      }

      await Task.WhenAll(jobs);

      //Or Task.WhenAll(jobs).ContinueWith({AN ACTION CALLBACK}) 
      //if you want to keep the return as a void;
}

现在,您可以在调用该方法的任何地方等待FillResults函数,也可以使用另一个回调来处理