Что лучше использовать HttpClient или WebRequest в ASP.NET Core для асинхронного удаленного чтения содержимого файла построчно? - PullRequest
0 голосов
/ 05 ноября 2018

Я планирую читать удаленный файл построчно асинхронно, используя https://github.com/Dasync/AsyncEnumerable (поскольку пока нет асинхронных потоков [C # 8 возможно]: https://github.com/dotnet/csharplang/blob/master/proposals/async-streams.md):

public static class StringExtensions
{
    public static AsyncEnumerable<string> ReadLinesAsyncViaHttpClient(this string uri)
    {
        return new AsyncEnumerable<string>(async yield =>
        {
            using (var httpClient = new HttpClient())
            {
                using (var responseStream = await httpClient.GetStreamAsync(uri))
                {
                    using (var streamReader = new StreamReader(responseStream))
                    {
                        while(true)
                        {
                            var line = await streamReader.ReadLineAsync();

                            if (line != null)
                            {
                                await yield.ReturnAsync(line);
                            }
                            else
                            {
                                return;
                            }
                        } 
                    }
                }
            }
        });
    }
    public static AsyncEnumerable<string> ReadLinesAsyncViaWebRequest(this string uri)
    {
        return new AsyncEnumerable<string>(async yield =>
        {
            var request = WebRequest.Create(uri);
            using (var response = request.GetResponse())
            {
                using (var responseStream = response.GetResponseStream())
                {
                    using (var streamReader = new StreamReader(responseStream))
                    {
                        while(true)
                        {
                            var line = await streamReader.ReadLineAsync();

                            if (line != null)
                            {
                                await yield.ReturnAsync(line);
                            }
                            else
                            {
                                return;
                            }
                        } 
                    }
                }
            }
        });
    }
}

Кажется, что они оба прекрасно работают в простом консольном приложении, как показано ниже:

public class Program
{
    public static async Task Main(string[] args)
    {
        // Or any other remote file
        const string url = @"https://gist.githubusercontent.com/dgrtwo/a30d99baa9b7bfc9f2440b355ddd1f75/raw/700ab5bb0b5f8f5a14377f5103dbe921d4238216/by_tag_year.csv";

        await url.ReadLinesAsyncViaWebRequest().ForEachAsync(line =>
        {
            Console.WriteLine(line, Color.GreenYellow);
        });
        await url.ReadLinesAsyncViaHttpClient().ForEachAsync(line =>
        {
            Console.WriteLine(line, Color.Purple);
        });
    }
}

... но у меня есть некоторые опасения, если он используется как часть ASP.NET Core WebAPI для обработки строк, а затем проталкивает их с помощью PushStreamContent:

Идея состояла бы в том, чтобы иметь конвейер данных, который использует async / await, чтобы число используемых потоков было как можно меньше, а также чтобы избежать увеличения памяти (которое использует как перечислимый особенность AsyncEnumerable).

Я прочитал несколько статей, но кажется, что это не версии .NET Core, и я не знаю, будут ли какие-то потенциальные проблемы с производительностью в отношении того, чего я хотел бы достичь?

Примером "бизнес" случая будет:

using System;
using System.Collections.Async;
using System.IO;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;

namespace WebApplicationTest.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class DumbValuesController : ControllerBase
    {
        private static readonly Random Random = new Random();

        // GET api/values
        [HttpGet]
        public async Task<IActionResult> DumbGetAsync([FromQuery] string fileUri)
        {
            using (var streamWriter = new StreamWriter(HttpContext.Response.Body))
            {
                await fileUri.ReadLinesAsyncViaHttpClient().ForEachAsync(async line =>
                {
                    // Some dumb process on each (maybe big line)
                    line += Random.Next(0, 100 + 1);
                    await streamWriter.WriteLineAsync(line);
                });
            }

            return Ok();
        }
    }
}

1 Ответ

0 голосов
/ 05 ноября 2018

У нас есть доступ к исходному коду для .NET Core. Так вы можете посмотреть.

Базовая реализация обоих в конечном итоге использует HttpClientHandler (реализация этого класса разбита на 4 файла).

Это видно из исходного кода HttpClient и HttpWebRequest (который WebRequest использует ).

Так что я подозреваю, что вы не заметите никакой разницы в производительности.

HttpClient - последний из написанных, поэтому его использование приветствуется. И по причинам, указанным в статье, на которую вы ссылаетесь: http://www.diogonunes.com/blog/webclient-vs-httpclient-vs-httpwebrequest/

...