小编典典

在 HttpClient 和 WebClient 之间做出决定

all

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

我们需要使用供应商提供的 REST 服务。我正在评估在 .Net 4.0 中调用 REST 服务的最佳方式。REST 服务需要基本身份验证方案,它可以返回 XML 和 JSON 格式的数据。不需要上传/下载大量数据,将来我也看不到任何东西。我查看了一些用于 REST 消费的开源代码项目,并没有发现任何价值来证明项目中的额外依赖是合理的。开始评估WebClientHttpClient。我从 NuGet 下载了 .Net 4.0 的 HttpClient。

我搜索了和之间的区别WebClient这个站点提到单个 HttpClient 可以处理并发调用,它可以重用解析的 DNS、cookie 配置和身份验证。我还没有看到我们可能因差异而获得的实际价值。HttpClient

我进行了快速性能测试以了解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);
        }
    }
}

我的问题

  1. REST 调用在 3-4 秒内返回,这是可以接受的。对 REST 服务的调用是在从 ajax 调用中调用的控制器方法中启动的。首先,调用在不同的线程中运行并且不会阻塞 UI。那么,我可以坚持使用同步呼叫吗?
  2. 上面的代码是在我的 localbox 中运行的。在产品设置中,将涉及 DNS 和代理查找。使用HttpClientover有什么好处WebClient吗?
  3. 并发HttpClient比? WebClient从测试结果来看,我看到 WebClient同步调用表现更好。
  4. 如果我们升级到 .Net 4.5会HttpClient是更好的设计选择吗?性能是关键的设计因素。

阅读 266

收藏
2022-02-25

共1个答案

小编典典

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

  • 有一个很好的异步编程模型
  • 由 Henrik F Nielson 进行工作,他基本上是 HTTP 的发明者之一,他设计了 API,因此您可以轻松地遵循 HTTP 标准,例如生成符合标准的标头
  • 在 .Net 框架 4.5 中,因此它对可预见的未来有一定程度的支持
  • 如果您想在其他平台(.Net 4.0、Windows Phone 等)上使用它,还具有该库的 xcopyable/portable-framework 版本。

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

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

2022-02-25