我使用
中概述的方法从数据库生成一个非常大的.csv文件https://stackoverflow.com/a/13456219/141172
它工作正常,达到一定程度。当导出的文件太大时,我会得到OutOfMemoryException
。
如果我通过修改这样的代码来关闭输出缓冲:
protected override void WriteFile(System.Web.HttpResponseBase response)
{
response.BufferOutput = false; // <--- Added this
this.Content(response.OutputStream);
}
文件下载完成。但是,与启用输出缓冲时相比,它的几个数量级更慢(在localhost上测量缓冲为真/假的同一文件)。
我明白这个速度较慢,但为什么它会慢慢相对爬行呢?我能做些什么来提高处理速度吗?
更新
如评论中所建议的,使用File(Stream stream, String contentType)也是一种选择。但是,我不确定如何创建stream
。数据是基于数据库查询动态组合的,而MemoryStream将耗尽连续的物理内存。欢迎提出建议。
更新2
在评论中建议,交替从数据库中读取并写入流会导致性能下降。我修改了代码以在单独的线程中执行流写入(使用生产者/消费者模式)。性能没有明显差异。
答案 0 :(得分:7)
我不知道ASP.NET和IIS在输出流方面做了什么,但可能正在使用太小的块。挂钩BufferedStream
有一个非常大的缓冲区,比如4MB。
根据你的意见,它有效。现在,调低缓冲区大小以节省内存并使用较小的工作集。适合缓存。
作为主观评论,我很失望,这甚至是必要的。 IIS应该自动使用正确的缓冲区,这对于TCP连接非常容易。
从OP编辑
以下是从此回答中获得的代码
public ActionResult Export()
{
// Domain specific stuff here
return new FileGeneratingResult("MyFile.txt", "text/text",
stream => this.StreamExport(stream), false);
}
private void StreamExport(Stream stream)
{
using (BufferedStream bs = new BufferedStream(stream, 256*1024))
using (StreamWriter sw = new StreamWriter(bs))
foreach (var stuff in MyData())
{
sw.Write(stuff);
}
}
答案 1 :(得分:0)
在Eric的最新更新中,他提到使用另一个线程。我也有实现数据库导出的问题。以下是我使用的解决方案的一些示例代码: