У меня есть список URL-адресов. Я запускаю OpenreadAsyn (url1) для OpenReadAsync (urlN) .. Как мне ждать завершения всех из них - PullRequest
0 голосов
/ 19 января 2019

У меня есть список результатов длиной N. У меня есть список URL из N URL.Мне нужно выполнить следующую операцию.

            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 голосов
/ 19 января 2019

Есть два решения.Быстрым и грязным было бы добавить счетчик, чтобы указать количество оставшихся заданий, которое будет увеличиваться, как и прежде, вызывать GetResponse и уменьшаться в пределах обратного вызова, а если оно достигает 0, вызовите следующий шаг в вашем процессе.Это было бы рискованно из-за состояния гонки и непредсказуемого поведения потока, например, если вы вызываете один запрос и до того, как второй запрос начнется, а затем он попытается продолжить.

Лучшим решением было бы отслеживатьЗадачи, созданные с помощью OpenReadTaskAsync вместо OpenReadAsync, а затем с помощью Task.WhenAll({ALL YOUR TASKS}).

Это немного изменит вашу программу:

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

...

GetResponse должен будет вернуть значение задачи, которое является простым.

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, где бы вы ни вызывали этот метод, либо иметь другой обратный вызов для обработки завершения

...