在 HttpClient 和 WebClient 之间做出决定 [关闭]

2024-02-04

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

我们需要使用供应商提供的 REST 服务。我正在评估在 .NET 4.0 中调用 REST 服务的最佳方式。 REST 服务需要基本的身份验证方案,并且可以返回 XML 和 JSON 格式的数据。

没有任何上传/下载大量数据的要求,而且我未来也看不到任何东西。我查看了一些用于 REST 使用的开源代码项目,但没有发现其中有任何价值可以证明项目中的额外依赖项是合理的。我开始评价WebClient and HttpClient。我从下载了 .NET 4.0 的 HttpClientNuGet https://en.wikipedia.org/wiki/NuGet.

我寻找之间的差异WebClient and HttpClient and 这个网站 https://web.archive.org/web/20140217233914/http://blogs.k10world.com/technology/webclient-httpclient-consume-http-requests/提到单个 HttpClient 可以处理并发调用,并且可以重用已解析的 DNS、cookie 配置和身份验证。我还没有看到我们可能因差异而获得的实际价值。

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

我正在使用相同的HttpClient所有请求的实例(最小 - 最大)。

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

使用新的HttpClient对于每个请求(最小值 - 最大值):

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

Code

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 服务在控制器方法中启动,该方法被调用 阿贾克斯呼叫。首先,调用在不同的线程中运行,并且不会阻塞 UI。那么,我可以坚持使用同步调用吗?
  2. 上面的代码是在我的本地盒子中运行的。在生产设置中,DNS 和代理 会涉及到查找。使用有什么好处吗HttpClient over WebClient?
  3. Is HttpClient并发性优于WebClient?从测试结果来看WebClient同步调用性能更好。
  4. Will HttpClient如果我们升级到 .NET 4.5,会是更好的设计选择吗?性能是关键的设计因素。

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

  • 具有良好的异步编程模型
  • 由 Henrik F Nielson 负责,他基本上是 HTTP 的发明者之一,他设计了 API,因此您可以轻松遵循 HTTP 标准,例如生成符合标准的标头
  • 位于 .NET Framework 4.5 中,因此它在可预见的未来具有一定程度的有保证的支持
  • 还有xcopy https://ss64.com/nt/xcopy.html如果您想在其他平台上使用该库的able/portable-framework版本 - .NET 4.0,Windows 手机 https://en.wikipedia.org/wiki/Windows_Phone, etc.

如果您正在编写一个对其他 Web 服务进行 REST 调用的 Web 服务,您应该希望对所有 REST 调用使用异步编程模型,这样就不会出现线程匮乏的情况。您可能还想使用最新的 C# 编译器,它具有异步/等待 https://en.wikipedia.org/wiki/Async/await支持。

注意:据我所知,它的性能并没有更高。如果您创建一个公平的测试,它的性能可能会有些相似。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

在 HttpClient 和 WebClient 之间做出决定 [关闭] 的相关文章

随机推荐

  • Jenkins Pipeline 不与 docker-compose 一起运行,因为它无法连接到 docker 守护进程

    我正在尝试构建 docker 映像并在 Jenkins 管道内使用 docker compose 启动容器 我有一个适用于 Jenkins 的自定义 docker 映像 其中我使用开箱即用的 Jenkins 映像并安装 Docker CE
  • 使用 C 或 C++ 从控制台获取原始输入

    Initialize new terminal i o settings static struct termios old new1 void initTermios int echo tcgetattr 0 old grab old t
  • Javascript jQuery:查找字符串中的数组元素

    我认为我的问题相当简单 但我对 Javascript 不太有经验 我想做的是提取页面的源代码并将其全部粘贴到变量中 var sourcecode document documentElement innerHTML 然后我有一个术语数组 我
  • npm 安装 package.json 中指定的确切包版本

    目前 如果我跑npm install 它会安装已安装软件包的更新版本 如何安装中指定的确切版本package json file 默认情况下 npm 使用 安装软件包 这意味着同一主要范围内的任何版本 您可以使用 save exact 切换
  • 模拟网络服务

    我们有两个组件 企业应用程序 X 和 Web 服务 Y 我们希望制作我们的 自动化 测试工具 仅测试应用程序 X 与 Y 交互 并且我们没有可用的网络服务 Y Notes 测试工具将是一个桌面应用程序 我们不想使用其他外部工具 例如Soap
  • 隐藏同一类的所有特定 div 的角度方式是什么

    我想做一件简单的事情 我有一个应用程序 它有某些需要显示的div 仅特定的一个 并且如果单击它之外的某处则隐藏 例如 所有特定的类 使用 jquery 这很容易 some class style display none psuedo co
  • 计算列表中每个项目之间的相关性

    我正在尝试计算列表中每个项目之间的皮尔逊相关性 我试图获取数据 0 和数据 1 数据 0 和数据 2 以及数据 1 和数据 2 之间的相关性 import scipy from scipy import stats data 1 2 4 9
  • 用 TextViews 解决椭圆问题

    哇SDK 哇 因此 我尝试在 TextView 单行 运行到屏幕外之前在其末尾添加一个椭圆 我读到省略号已损坏 为 2 1 开发 经过Google搜索 每个人似乎都建议将inputType设置为text 将maxLines设置为1 你会得到
  • HTML5 视频标签在 Safari、iPhone 和 iPad 中不起作用

    我正在尝试创建一个 html5 网页 其中有一个像 13s 这样的小视频 我将该视频的 flash 版本转换为 3 种格式 使用 fireFogg 的 ogv 使用 firefogg 的 webm 以及使用 HandBrake 应用程序 h
  • Vue中的页面滑动过渡?

    我正在使用 Vue js 构建一个应用程序 我想为其提供更多类似本机的视图 如何添加页面幻灯片切换 我当前的代码
  • PySide 入门 [关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 我决定学习 Python Gui 开发 由于 PyQt 不是免费的 所以选择了 PySide 但是 与 PyQt 不同 PySide 没有
  • 使用 jQuery mobile 下载文件

    我对 jquery mobile 相当陌生 在尝试链接 jquery mobile 项目中的文件进行下载时遇到错误 我希望用户能够从应用程序下载 zip 文件 但要么出现页面加载错误 要么在新页面中显示未定义 我尝试使用锚标记来链接要下载的
  • f:convertNumber 不会对十进制尾随字母字符引发转换错误

    我在用
  • 无法调用插入的 Javascript 片段

    我正在尝试将 Javascript 片段插入网页 然后使用 blue prism 调用它 这样做的目的是分析搜索返回哪些元素 以确定整个流程中下一步该去哪里 我已经使用 IE 11 开发者控制台在目标网站上测试了 Javascript 代码
  • 在 digitalocean 上安装 PHP 7

    我尝试在 digitalocean 上使用 PHP 7 但文件内的脚本无法运行 这是我用来安装的 sudo apt get install php7 libapache2 mod php7 php7 mcrypt 我可以执行 php ver
  • .NET:无法将对象转换为它实现的接口

    我有一个类 TabControlH60 它既继承自基类 UserControl 又实现了一个接口 IFrameworkClient 我使用 NET Activator 类实例化该对象 使用返回的实例 我可以转换为 UserControl 基
  • signpass 错误:找不到 pass.com.xxx.xxxx 的身份

    我使用Apple 存折演示passbook materials 中的signpass 来创建一个 pkpass 文件 我已创建了我的通行证类型ID 并更改了pass json 中的passTypeIdentity 当我执行时 signaps
  • C语言中如何判断一个进程是否正在运行?

    我想知道某个进程是否正在运行 我不想使用任何系统 命令 是否有任何基于 C 的函数可以让您知道进程是否正在运行 我想提供进程名称并想知道它是否正在运行 Thanks 当然可以 使用kill 2 http man7 org linux man
  • SQLALCHEMY - 迭代数据

    当我使用 SQLALchemy 时 如何迭代列名 Eg Column Name 1 Column Name 2 Column Name 3 etc 第二个问题是我有以下查询 root dbsession query MyTable filt
  • 在 HttpClient 和 WebClient 之间做出决定 [关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 我们的 Web 应用程序在 NET Framework 4 0 中运行 UI 通过 Ajax 调用来调用控制器方法 我们需要使用供应商