【问题标题】:How to lower memory usage in FileStreamResult api如何降低 FileStreamResult api 中的内存使用率
【发布时间】:2020-02-04 19:12:39
【问题描述】:

现在我有一个 api 可以得到很多结果(800k),它应该将它们解析并流式传输为 CSV。 我拥有的(某种)工作代码是这样的

            var query = context.address.AsNoTracking();

            MemoryStream memoryStream = new MemoryStream();
            StreamWriter writer = new StreamWriter(memoryStream);

              foreach (var row in query)
            {
                writer.WriteLine(row.Name+","+row.Surname+","+row.BirthDate);

            }

            writer.Flush();                                 
            memoryStream.Seek(0, SeekOrigin.Begin);
            return new FileStreamResult(memoryStream, "application/octet-stream")
            {
                FileDownloadName = "DataFile.csv"
            };

但是,这似乎将所有内容都放入内存,并使用 300 mb 的内存进行存储。 据我了解,这发生在 foreach 语句中。有没有办法让我写下这条线,流式传输它,然后从内存中处理它?我的目标是在不使用太多内存的情况下实现类似的目标

我也试过这种方式,一次通话有效, 但是如果同时进行多个api调用,就会出现奇怪的行为

 public async Task makeDif()
    {




            //var query = context.Adresar.AsNoTracking();
        var query = context.Adresar.Select(x => string.Join(",", x.Ime, x.Prezime, x.Datarag + Environment.NewLine)).AsNoTracking();
        Response.ContentType = "application/json";
        Response.BodyWriter.WriteAsync(Encoding.UTF8.GetBytes("ime,prezime,datarag" + Environment.NewLine)); 
        foreach (var row in query)
                {
               await Response.BodyWriter.WriteAsync(Encoding.UTF8.GetBytes(row));

            }}

【问题讨论】:

  • 您可以使用临时文件来缓冲结果吗?所以首先写入文件,而不是内存流,然后使用Response.TransmitFile(filePath)进行传输
  • 我想这可能是一种解决方法,但仍然不能完全解决我的 .我尝试使用 yield return 来执行此操作,但这不会返回完整的 csv 文件,而是返回很多行。
  • 问题是MemoryStream,而不是FileStreamResult。该代码在返回之前将所有内容缓存在内存中。一个快速简单的解决方法是将数据导出到一个临时文本文件并返回该文件

标签: c# asp.net-core .net-core entity-framework-core


【解决方案1】:

您可以直接将数据写入响应正文,而无需将其放入 MemoryStream。

提问者编辑: 这就是我所做的

//var query = context.Adresar.AsNoTracking();
var query = context.Adresar.Select(x => string.Join(",", x.Ime, x.Prezime, x.Datarag + Environment.NewLine)).AsNoTracking();
Response.ContentType = "application/json";
Response.BodyWriter.WriteAsync(Encoding.UTF8.GetBytes("ime,prezime,datarag" + Environment.NewLine)); 
foreach (var row in query)
{
    await Response.BodyWriter.WriteAsync(Encoding.UTF8.GetBytes(row));
}

它似乎工作正常

【讨论】:

  • 是返回 Ok(query) 吗?因为我已经尝试过了。
  • Response.ContentType = "application/json"; Response.BodyWriter.WriteAsync(Encoding.UTF8.GetBytes("ime,prezime,datarag" + Environment.NewLine)); foreach (var row in query) { Response.BodyWriter.WriteAsync(Encoding.UTF8.GetBytes(row));像这样尝试过,一个请求可以正常工作,但是对于多个请求,它似乎返回越来越多的数据,一个请求返回 30mb(应该如此),但多个请求返回千兆字节的数据。这是否与异步方法有关?
  • 您应该“等待”异步写入,IMO。但即便如此,我不确定异步是否应该是结果大小爆炸的原因。
  • 正如 ben_a_adams 所说的here .. 如果您导入using Microsoft.AspNetCore.Http;,您可以直接使用Response.WriteAsync(row) 传递字符串
猜你喜欢
  • 1970-01-01
  • 2018-12-13
  • 1970-01-01
  • 1970-01-01
  • 2023-03-27
  • 2013-10-03
  • 2016-06-11
  • 2012-09-01
  • 2019-01-23
相关资源
最近更新 更多