【问题标题】:ASP.NET Web API 2 - StreamContent is extremely slowASP.NET Web API 2 - StreamContent 非常慢
【发布时间】:2016-01-04 16:13:41
【问题描述】:

我们已将一个项目从 WCF 移植到 Web API (SelfHost),在此过程中,我们注意到在提供 Web 应用程序时速度大大降低。现在是 40-50 秒,而之前是 3 秒。

我通过使用以下控制器为 AspNet.WebApi 和 OwinSelfHost 添加各种 Nuget 包,在一个简单的控制台应用程序中重现了该问题:

var stream = new MemoryStream();
using (var file = File.OpenRead(filename))
{
    file.CopyTo(stream);
}
stream.Position = 0;

var response = Request.CreateResponse(System.Net.HttpStatusCode.OK);

/// THIS IS FAST
response.Content = new ByteArrayContent(stream.ToArray());
/// THIS IS SLOW
response.Content = new StreamContent(stream);

response.Content.Headers.ContentType = new MediaTypeHeaderValue(System.Web.MimeMapping.GetMimeMapping(filename));            
response.Content.Headers.ContentLength = stream.Length;

从代码中可以看出,唯一的区别是 StreamContent (slooooow) 与 ByteArrayContent 的用法。

该应用程序托管在 Win10 机器上,可从我的笔记本电脑访问。 Fiddler 显示,使用 StreamContent 将单个 1MB 文件从服务器获取到我的笔记本电脑需要 14 秒,而 ByteArrayContent 不到 1 秒。

另请注意,将完整的文件读入内存以显示唯一的区别是使用的 Content 类。

奇怪的是,似乎它的传输本身很慢。服务器快速/立即响应标头,但数据需要很长时间才能到达,如 Fiddler 计时信息所示:

GotResponseHeaders: 07:50:52.800
ServerDoneResponse: 07:51:08.471

完整的计时信息:

== TIMING INFO ============
ClientConnected:    07:50:52.238
ClientBeginRequest: 07:50:52.238
GotRequestHeaders:  07:50:52.238
ClientDoneRequest:  07:50:52.238
Determine Gateway:  0ms
DNS Lookup:         0ms
TCP/IP Connect:     15ms
HTTPS Handshake:    0ms
ServerConnected:    07:50:52.253
FiddlerBeginRequest:07:50:52.253
ServerGotRequest:   07:50:52.253
ServerBeginResponse:07:50:52.800
GotResponseHeaders: 07:50:52.800
ServerDoneResponse: 07:51:08.471
ClientBeginResponse:07:51:08.471
ClientDoneResponse: 07:51:08.471

Overall Elapsed:    0:00:16.233

有谁知道背后发生了什么可以解释行为差异的原因?

【问题讨论】:

  • 嗨,我在这里遇到了完全相同的问题。同时你找到解决方案了吗?
  • @DanielG:恐怕不是,但我在这里发布了一个错误报告:connect.microsoft.com/VisualStudio/feedback/details/1932717/…。如果您对其进行投票并单击“我也可以”链接(在 Repros 旁边),那就太好了。
  • 好的,会这样做。一个问题:如果数据已经在内存中,为什么不只使用 ByteArrayContent 呢?
  • 尝试调整 StreamContent 缓冲区大小 (msdn.microsoft.com/en-us/library/hh193591(v=vs.118).aspx)。默认只有 4kb,这会导致很多写操作。
  • @hiFI 我使用 Fiddler。 ...但是数据需要很长时间才能到达,如 Fiddler 计时信息所示

标签: c# asp.net asp.net-web-api


【解决方案1】:

我的 OWIN 自托管问题的解决方案是 StreamContent 缓冲区大小。 StreamContent 的默认构造函数使用默认值 0x1000,4Kb。在千兆网络上,以约 60Kb/s 的速率传输 26Mb 文件需要约 7 分钟。

 const int BufferSize = 1024 * 1024;
 responseMessage = new HttpResponseMessage();
 responseMessage.Content = new StreamContent(fileStream, BufferSize);

现在将 bufferSize 修改为 1Mb 只需几秒钟即可完成下载。

[编辑] 在 StreamContent SerializeToStreamAsync 中执行 StreamToStreamCopy,根据this link,性能会有所不同。一个合适的值可能是 80K。

【讨论】:

    【解决方案2】:

    我在这里面临同样的问题,我认为这与 Owin 自托管有关。我刚刚创建了一个 Asp.net 示例应用程序并将其托管在 IIS 上。在这种情况下,它按预期工作。

    下载 80 MB 文件时我的测试系统上的结果:

    • 使用 Streamcontent 和 SelfHosting:~20 分钟
    • 使用 ByteArrayContent 和自托管:
    • 使用 Streamcontent 和 IIS 托管:

    在我的自托管项目中缺少 ASP.net 中的配置设置,或者我猜在 owin 自托管代码中存在错误。

    【讨论】:

      【解决方案3】:

      当您编译项目时,请尝试从调试更改为发布。这是一个长期的尝试,但肯定会提高一点性能。

      【讨论】:

      • 恐怕没有区别。
      猜你喜欢
      • 2017-11-24
      • 1970-01-01
      • 1970-01-01
      • 2012-01-05
      • 2023-03-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多