多个Response.writeAsync调用 [英] Multiple Response.writeAsync Calls

查看:176
本文介绍了多个Response.writeAsync调用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在研究Asp.Net Security,发现了一些令人惊讶的代码:

I have been researching Asp.Net Security and I found some surprising code:

context.Response.ContentType = "text/html";
await context.Response.WriteAsync("<html><body>");
await context.Response.WriteAsync("An remote error has occured: " + context.Request.Query["ErrorMessage"] + "<br>");
await context.Response.WriteAsync("<a href=\"/\">Home</a>");
await context.Response.WriteAsync("</body></html>");

令我惊讶的是,短字符串多次调用WriteAsync.

What surprised me is the multiple calls to WriteAsync with short strings.

我本可以使用具有String.Format或StringBuilder的模板来连接字符串,然后在一次调用中将其写入:

I would have used a template with String.Format or a StringBuilder to concatenate the strings and then write that in a single call:

var template = @"
<html><body>
An remote error has occured:{0}<br>
<a href=\"/\">Home</a>
</body></html>
";

var html = string.format(template, context.Request.Query["ErrorMessage"]);
await context.Response.WriteAsync(html);

我观察到的差异

  • 我的代码更容易修改.
  • 我还有一些空白.
  • 我的代码使用较大的硬编码字符串,而不是一堆小的硬编码字符串.
  • 我使用String.Format,与串联相比,它可能对性能有影响.
  • 如果应避免字符串串联,则应将该部分分解:

    The differences I observe

    • My code is much easier to modify.
    • I've got some extra white-space.
    • My code uses a larger hard-coded string instead of a bunch of small hard-coded strings.
    • I use String.Format which may have a performance hit compared to concatenation.
    • If string concatenation should be avoided, this part should be broken up:

      "An remote error has occured: " + context.Request.Query["ErrorMessage"] + "<br>"
      

    • 出于讨论目的.假设这是在平均同时有10,000个活动用户的Web服务器的上下文中进行的,因此性能非常重要.

      For the purposes of discussion. Let's assume that this is in the context of a web server with an average of ~10,000 simultaneous active users: So performance is important.

      • 为什么这样做?
      • 它如何影响性能?
      • 什么时候应该等待而不是Response.Write来调用Response.WriteAsync?
      • 应多久调用一次Response.WriteAsync?
        • 尽可能少地处理少量数据
        • 仅当大量文本准备就绪时
        • Why is this done like this?
        • How does it affect performance?
        • When should await Response.WriteAsync be called instead of Response.Write?
        • How often should Response.WriteAsync be called?
          • As often as possible with tiny amounts of data
          • Only when a large amount of text is ready

          推荐答案

          我创建了一个Azure网站(在Basic 1-1 Small Instance上运行)对此进行基准测试.然后,我使用 https://loader.io 上的免费服务在1分钟内以100个用户/秒的速度运行了每个测试.

          I created an Azure website (running on Basic 1 - 1 Small Instance) to benchmark this. Then I used the free service at https://loader.io to run each test at 100 users/second over 1 minute.

          我以不同的顺序运行了每个测试3次.每次测试的时间间隔都在200毫秒之内.

          I ran each test 3 times in different orders. The times for each test run were within 200ms of each other.

          结果很明显: StringBuilder取得了重大胜利.每个异步调用的开销都远远超过了任何形式的字符串连接的开销(甚至String.Format的性能也比多个异步调用要好).

          The results were clear: StringBuilder won significantly. The cost of each async call far out weighs the cost of any form of string concatenation (even String.Format performed better than the multiple async calls).

          • 1992ms-StringBuilder.Append
          • 3071ms-StringBuilder.AppendFormat
          • 4257ms-具有String.Format的WriteAsync
          • 9265毫秒-WriteAsync

          这是每个测试的代码:

              // Do not write this code - It is ugly and performs terribly
              private async Task TestWriteAsync(HttpContext context)
              {
                  var r = context.Response;
          
                  var id = "id";
                  var size = "12";
                  var text = "text";
          
                  await r.WriteAsync("<div style='display:none'>");
          
                  for (int i = 0; i < 10000; i++)
                  {
                      await r.WriteAsync("<li id='");
                      await r.WriteAsync(id);
                      await r.WriteAsync("' style='font-size:");
                      await r.WriteAsync(size);
                      await r.WriteAsync("'>");
                      await r.WriteAsync(text);
                      await r.WriteAsync("</li>");
                  }
          
                  await r.WriteAsync("</div>");
              }
          
              // This is much better, but still not great
              private async Task TestWriteAsyncFormat(HttpContext context)
              {
                  var r = context.Response;
          
                  var id = "id";
                  var size = "12";
                  var text = "text";
                  var template = "<li id='{0}' style='font-size:{1}'>{2}</li>";
          
                  await r.WriteAsync("<div style='display:none'>");
          
                  for (int i = 0; i < 10000; i++)
                  {
                      await r.WriteAsync(string.Format(template, id, size, text));
                  }
          
                  await r.WriteAsync("</div>");
              }
          
              // The Performance Winner, but ugly code
              private async Task TestStringBuilder(HttpContext context)
              {
                  var sb = new StringBuilder();
          
                  var id = "id";
                  var size = "12";
                  var text = "text";
          
                  sb.Append("<div style='display:none'>");
          
                  for (int i = 0; i < 10000; i++)
                  {
                      sb.Append("<li id='");
                      sb.Append(id);
                      sb.Append("' style='font-size:");
                      sb.Append(size);
                      sb.Append("'>");
                      sb.Append(text);
                      sb.Append("</li>");
                  }
          
                  sb.Append("</div>");
          
                  await context.Response.WriteAsync(sb.ToString());
              }
          
              // Decent performance and Clean Code
              private async Task TestStringBuilderFormat(HttpContext context)
              {
                  var sb = new StringBuilder();
          
                  var id = "id";
                  var size = "12";
                  var text = "text";
                  var template = "<li id='{0}' style='font-size:{1}'>{2}</li>";
          
                  sb.Append("<div style='display:none'>");
          
                  for (int i = 0; i < 10000; i++)
                  {
                      sb.AppendFormat(template, id, size, text);
                  }
          
                  sb.Append("</div>");
          
                  await context.Response.WriteAsync(sb.ToString());
              }
          

          因此,尽管旧的"Response.Write"要比具有同步请求的StringBuilder快,但"await Response.WriteAsync"要慢得多(由于异步开销).

          So although the old "Response.Write" is faster than StringBuilder with synchronous requests, "await Response.WriteAsync" is much slower (because of the async overhead).

          这篇关于多个Response.writeAsync调用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆