在我的小文件传输网站(this one,运行.NET 4.5.1)中,我按照Microsoft知识库文章812406将以前上传的文件从服务器发送到浏览器。
进行性能优化我很惊讶发现这行
var buffer = new byte[10000];
需要相当长的一段时间(我使用红门' s ANTS Performance Profiler)。缓冲区仅在每个完整下载/客户端分配一次。
我的问题:
更新1:
感谢您的评论我已经看到内存也在循环内部分配。
尽管如此,ANTS Profiler只标记循环外 的分配需要花费那么多时间,但老实说我还不明白。我已经删除了循环中的(无意义的)分配。
更新2:
实施了建议的BufferManager
并将缓冲区大小从10k减少到4096(以防万一......),我的网站运行起来非常顺利。
答案 0 :(得分:4)
在.NET中创建对象通常非常快,但由于此数组对象具有较大的大小,因此清除其所有字节需要很长时间。 C#始终将所有字节设置为0
,从而在创建对象时将所有字段设置为其默认值。 (构造函数和字段初始值设定项当然可以在类和结构中分配不同的值。)
在example given by Microsoft中,缓冲区在循环之前分配,永远不会改变其大小。此外,写入输出流只会写入所需的字节。
// Gets the exact number of bytes read
length = iStream.Read(buffer, 0, 10000);
// Writes only 'length' bytes to the output
Response.OutputStream.Write(buffer, 0, length);
因此,无需通过在每次循环迭代中分配新缓冲区来“清除”缓冲区。脏的额外字节不会受到伤害。
解决方案:将行buffer= new Byte[10000];
放入while循环!
答案 1 :(得分:3)
是。实际上,WCF uses a "buffer manager" to prevent this problem。
我一直在开发network service,在分析过程中,我发现Byte[]
缓冲区的分配造成了瓶颈。不仅在分配期间,而且处理器在GC中浪费的时间也非常高。重用这些缓冲区并避免分配的改进可以带来非常大的性能提升。
您可以使用BufferManager
类来避免编写自己的缓冲区管理策略。
答案 2 :(得分:1)
调用这样的构造函数,尤其是使用如此大的缓冲区,肯定会花费大量的CPU时间。当然,你的问题的答案将基于意见,但这是我的:
分配该大小的缓冲区没有任何问题。 10K在现代系统上并没有那么多的记忆。当然,在任何类型的循环中这样做都会很快耗尽CPU时间。
如果可以,请尽量避免为每次使用重建缓冲区。使用先前定义的缓冲区可避免每次需要时重新分配内存。当然,如果这是线程化的(多个连接),每个连接/线程都需要自己的缓冲区,但至少每个连接有一个分配,而不是每个" chunk的新缓冲区"如链接示例中所示的流数据。
答案 3 :(得分:1)
如果您有文件传输任务,建议使用Microsoft.IO.RecyclableMemoryStream。
它具有RecyclableMemoryStreamManager类型,可以创建RecyclableMemoryStream(在内部重用字节)。
优点:
缺点: