Несколько веб-запросов, запустите другой запрос, ожидая ответа на последний. C # - PullRequest
0 голосов
/ 19 марта 2019

Я пытаюсь выполнить несколько веб-запросов с веб-сайтов, на загрузку которых уходит много времени (очень длинные файлы журнала).Я хочу реализовать метод, который будет продолжать создавать веб-запросы в ожидании ответа других и ускорить процесс.

Попытался реализовать метод асинхронного ожидания, но я не думаю, что он создает одновременные вызовы, а вместо этого он работает синхронно.Я очень запутался в том, как реализовать асинхронное ожидание, я смотрел на другие подобные вопросы, но все еще не очень ясно, как я могу исправить этот код для запуска асинхронного?
Это мой код:

        public static async Task<String> MakeRequestAsync(String url)
    {
        String responseText = null;

            try
            {
                HttpWebRequest request = WebRequest.Create(url) as HttpWebRequest;
                request.Proxy = null;
                WebResponse response = request.GetResponse();
                Stream responseStream = response.GetResponseStream();
                string sr = new StreamReader(responseStream).ReadToEnd();
                response.Close();
                responseStream.Close();
                responseText = sr;
            }

            catch (Exception e)
            {
                Console.WriteLine("Error: " + e.Message);
            }
        return responseText;
    }

..

private void button_test_Click(object sender, EventArgs e)
    {
         for (int n = 0; n < 5; n++)  //multiple requests
            {
                String a = AsyncTest().Result;
            }

    }

    private async Task<String> AsyncTest()
    {
        String b = await MakeRequestAsync(url);
        return b;
    }

Также любые предложения о том, как я могу ускорить этот процесс, были бы хорошими.

Ответы [ 2 ]

1 голос
/ 19 марта 2019

Ни один из ваших вызовов IO не является async. WebRequest также не имеет шаблона async/await, вы можете получить поведение async, используя BeginGetResponse с AsyncCallback, но есть лучший путь. Вместо этого используйте HttpClient, это рекомендуемый способ совершать http-звонки.

1010 * т.е. *

public static async Task<String> MakeRequestAsync(string url)
{

    using(var client = new HttpClient()) // don't do this, inject it as a singleton
    {
       using (var response = await client.GetAsync(url)
          return await response.Content.ReadAsStringAsync();
    }  
}

и затем измените ваш обработчик Click на async void:

private async void button_test_Click(object sender, EventArgs e)
{
     var tasks = new List<Task<string>>();
     for (int n = 0; n < 5; n++)  //multiple requests
     {
        tasks.Add(MakeRequestAsync(url));
     }
     await Task.WhenAll(tasks); // wait for all of them to complete;
     foreach(var task in tasks)
     {
         var str = await task; // or task.Result, won't block, already completed;
     }
}
0 голосов
/ 19 марта 2019

Вы должны использовать Microsoft Reactive Framework (он же Rx) - NuGet System.Reactive и добавить using System.Reactive.Linq; - тогда вы можете сделать это:

var query =
    from n in Observable.Range(0, 5)
    from r in Observable.Using(
        () => new WebClient(),
        wc => Observable.Start(() => wc.DownloadString($"{url}{n}")))
    select new { n, r };

IDisposable subscription =
    query
        .ToArray()
        .Select(xs => xs.OrderBy(x => x.n).Select(x => x.r).ToArray())
        .Subscribe(rs =>
        {
            /* Do something with the results */
        });

Это все многопоточное и неблокирующее.

Если вас не волнует порядок, в котором возвращаются результаты, просто сделайте следующее:

var query =
    from n in Observable.Range(0, 5)
    from r in Observable.Using(
        () => new WebClient(),
        wc => Observable.Start(() => wc.DownloadString($"{url}{n}")))
    select r;

IDisposable subscription =
    query
        .Subscribe(r =>
        {
            /* Do something with each result */
        });

Вызов subscription.Dispose() остановит запрос, если вам нужно отменить его.


Вы можете написать свой MakeRequestAsync метод следующим образом:

public static async Task<String> MakeRequestAsync(String url)
{
    return await
        Observable.Using(
            () => new WebClient(),
            wc => Observable.Start(() => wc.DownloadString(url)));
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...