首页 文章

在HttpClient和WebClient之间做出决定

提问于
浏览
166

我们的网络应用程序在.Net Framework 4.0中运行 . UI通过ajax调用调用控制器方法 .

我们需要从供应商处使用REST服务 . 我正在评估在.Net 4.0中调用REST服务的最佳方法 . REST服务需要基本身份验证方案,它可以返回XML和JSON中的数据 . 不需要上传/下载大量数据,我也没有找到任何值来证明项目中的其他依赖性 . 开始评估 WebClientHttpClient . 我从NuGet下载了用于.Net 4.0的HttpClient .

我搜索了 WebClientHttpClient 之间的区别,this site提到单个HttpClient可以处理并发调用,它可以重用已解析的DNS,cookie配置和身份验证 . 我还没有看到由于差异我们可能获得的实用 Value .

我做了一个快速的性能测试,以找出 WebClient (同步调用), HttpClient (同步和异步)如何执行 . 以下是结果:

对所有请求使用相同的 HttpClient 实例(最小 - 最大)

WebClient同步:8毫秒 - 167毫秒HttpClient同步:3毫秒 - 7228毫秒HttpClient异步:985 - 10405毫秒

为每个请求使用新的 HttpClient (最小 - 最大)

WebClient同步:4毫秒 - 297毫秒HttpClient同步:3毫秒 - 7953毫秒HttpClient异步:1027 - 10834毫秒

代码

public class AHNData
{
    public int i;
    public string str;
}

public class Program
{
    public static HttpClient httpClient = new HttpClient();
    private static readonly string _url = "http://localhost:9000/api/values/";

    public static void Main(string[] args)
    {
       #region "Trace"
       Trace.Listeners.Clear();

       TextWriterTraceListener twtl = new TextWriterTraceListener(
           "C:\\Temp\\REST_Test.txt");
       twtl.Name = "TextLogger";
       twtl.TraceOutputOptions = TraceOptions.ThreadId | TraceOptions.DateTime;

       ConsoleTraceListener ctl = new ConsoleTraceListener(false);
       ctl.TraceOutputOptions = TraceOptions.DateTime;

       Trace.Listeners.Add(twtl);
       Trace.Listeners.Add(ctl);
       Trace.AutoFlush = true;
       #endregion

       int batchSize = 1000;

       ParallelOptions parallelOptions = new ParallelOptions();
       parallelOptions.MaxDegreeOfParallelism = batchSize;

       ServicePointManager.DefaultConnectionLimit = 1000000;

       Parallel.For(0, batchSize, parallelOptions,
           j =>
           {
               Stopwatch sw1 = Stopwatch.StartNew();
               GetDataFromHttpClientAsync<List<AHNData>>(sw1);
           });
       Parallel.For(0, batchSize, parallelOptions,
            j =>
            {
                Stopwatch sw1 = Stopwatch.StartNew();
                GetDataFromHttpClientSync<List<AHNData>>(sw1);
            });
       Parallel.For(0, batchSize, parallelOptions,
            j =>
            {
                using (WebClient client = new WebClient())
                {
                   Stopwatch sw = Stopwatch.StartNew();
                   byte[] arr = client.DownloadData(_url);
                   sw.Stop();

                   Trace.WriteLine("WebClient Sync " + sw.ElapsedMilliseconds);
                }
           });

           Console.Read();
        }

        public static T GetDataFromWebClient<T>()
        {
            using (var webClient = new WebClient())
            {
                webClient.BaseAddress = _url;
                return JsonConvert.DeserializeObject<T>(
                    webClient.DownloadString(_url));
            }
        }

        public static void GetDataFromHttpClientSync<T>(Stopwatch sw)
        {
            HttpClient httpClient = new HttpClient();
            var response = httpClient.GetAsync(_url).Result;
            var obj = JsonConvert.DeserializeObject<T>(
                response.Content.ReadAsStringAsync().Result);
            sw.Stop();

            Trace.WriteLine("HttpClient Sync " + sw.ElapsedMilliseconds);
        }

        public static void GetDataFromHttpClientAsync<T>(Stopwatch sw)
        {
           HttpClient httpClient = new HttpClient();
           var response = httpClient.GetAsync(_url).ContinueWith(
              (a) => {
                 JsonConvert.DeserializeObject<T>(
                    a.Result.Content.ReadAsStringAsync().Result);
                 sw.Stop();
                 Trace.WriteLine("HttpClient Async " + sw.ElapsedMilliseconds);
              }, TaskContinuationOptions.None);
        }
    }
}

我的问题

  • REST调用以3-4s返回,这是可以接受的 . 调用REST服务是在从ajax调用调用的控制器方法中启动的 . 首先,调用在不同的线程中运行,不会阻止UI . 那么,我可以坚持同步电话吗?

  • 以上代码在我的localbox中运行 . 在prod设置中,将涉及DNS和代理查找 . 在 WebClient 上使用 HttpClient 有什么好处吗?

  • HttpClient 并发性比 WebClient 好吗?从测试结果来看,我看到 WebClient 同步调用的性能更好 .

  • 如果我们升级到.Net 4.5, HttpClient 会是更好的设计选择吗?性能是关键的设计因素 .

3 回答

  • 52

    我住在F#和Web API世界 .

    Web API发生了很多好事,特别是以安全性的消息处理程序等形式 .

    我知道我的意见只有一个,但 I would only recommend use of HttpClient for any future work . 也许有一些方法可以利用 System.Net.Http 中出现的其他部分,而不直接使用该程序集,但我无法想象这在当时是如何工作的 .

    Speaking of comparing these two

    • HttpClient比WebClient更接近HTTP .

    • HttpClient并不是Web客户端的完全替代品,因为有些事情包括报告进度,自定义URI方案以及WebClient提供的FTP调用 - 但是HttpClient没有 .

    enter image description here

    如果您使用的是.NET 4.5,请使用Microsoft为开发人员提供的HttpClient的async优度 . HttpClient与HTTP的服务器端兄弟非常对称,即HttpRequest和HttpResponse .

    更新:使用新HttpClient API的5个理由:

    • 强类型 Headers .

    • 共享缓存,Cookie和凭据

    • 访问cookie和共享cookie

    • 控制缓存和共享缓存 .

    • 将代码模块注入ASP.NET管道 . 清洁和模块化代码 .

    Reference

    C#5.0 Joseph Albahari

    (Channel9 - Video Build 2013)

    Five Great Reasons to Use the New HttpClient API to Connect to Web Services

    WebClient vs HttpClient vs HttpWebRequest

  • 2

    HttpClient是最新的API,它具有以下优点

    • 有一个很好的异步编程模型

    • 正在由Henrik F Nielson工作,他基本上是HTTP的发明者之一,他设计了API,因此您可以轻松地遵循HTTP标准,例如:生成符合标准的标头

    • 位于.Net框架4.5中,因此它对可预见的未来有一定程度的支持
      如果你想在其他平台上使用它,

    • 也有库的xcopyable / portable-framework版本 - .Net 4.0,Windows Phone等 .

    如果您正在编写一个对其他Web服务进行REST调用的Web服务,那么您应该为所有REST调用使用异步编程模型,这样就不会遇到线程饥饿问题 . 您可能还想使用具有async / await支持的最新C#编译器 .

    注意:它不是更高效的AFAIK . 如果你创建一个公平的测试,它可能有点类似的性能 .

  • 178

    首先,我不是WebClient与HttpClient的权威,特别是 . 其次,从您上面的评论中,似乎表明WebClient只是同步,而HttpClient是两者 .

    我做了一个快速的性能测试,以找到WebClient(同步调用),HttpClient(同步和异步)的执行方式 . 这是结果 .

    我认为这对于未来的思考是一个巨大的差异,即长时间运行的流程,响应式GUI等等(增加你在框架4.5中提出的好处 - 在我的实际经验中,在IIS上的速度非常快)

相关问题