【发布时间】:2019-03-18 20:25:19
【问题描述】:
我有以下基准,它使用堆栈分配、堆分配和 ArrayPool 分配从文件中读取字符串。
我希望堆栈分配最快,因为它只是堆栈指针增量,但根据基准 ArrayPool 稍快。
这怎么可能?
static void Main(string[] args)
{
BenchmarkRunner.Run<BenchmarkRead>();
}
using BenchmarkDotNet.Attributes;
using System;
using System.Buffers;
using System.IO;
using System.Linq;
namespace RealTime.Benchmark
{
[MemoryDiagnoser]
public class BenchmarkRead
{
const string TestFile = "TestFiles/animals.txt";
public BenchmarkRead()
{
Directory.CreateDirectory(Path.GetDirectoryName(TestFile));
// cca 100 KB of text
string content = string.Concat(Enumerable.Repeat("dog,cat,spider,cat,bird,", 4000));
File.WriteAllText(TestFile, content);
}
[Benchmark]
public void ReadFileOnPool() => ReadFileOnPool(TestFile);
[Benchmark]
public void ReadFileOnHeap() => ReadFileOnHeap(TestFile);
[Benchmark]
public void ReadFileOnStack() => ReadFileOnStack(TestFile);
public void ReadFileOnHeap(string filename)
{
string text = File.ReadAllText(filename);
// ....call parse
}
public void ReadFileOnStack(string filename)
{
Span<byte> span = stackalloc byte[1024 * 200];
using (var stream = File.OpenRead(filename))
{
int count = stream.Read(span);
if (count == span.Length)
throw new Exception($"Buffer size {span.Length} too small, use array pooling.");
span = span.Slice(0, count);
// ....call parse
}
}
public void ReadFileOnPool(string filename)
{
ArrayPool<byte> pool = ArrayPool<byte>.Shared;
using (var stream = File.OpenRead(filename))
{
long len = stream.Length;
byte[] buffer = pool.Rent((int)len);
try
{
int count = stream.Read(buffer, 0, (int)len);
if (count != len)
throw new Exception($"{count} != {len}");
Span<byte> span = new Span<byte>(buffer).Slice(0, count);
// ....call parse
}
finally
{
pool.Return(buffer);
}
}
}
}
}
结果:
| Method | Mean | Gen 0/1k Op | Gen 2/1k Op |Al. memory/Op|
|---------------- |---------:|------------:|------------:|------------:|
| ReadFileOnPool | 109.9 us | 0.1221 | - | 480 B |
| ReadFileOnHeap | 506.0 us | 87.8906 | 58.5938 | 393440 B |
| ReadFileOnStack | 115.2 us | 0.1221 | - | 480 B |
【问题讨论】:
-
这里真的有问题吗?简单地比较事物并不能真正帮助任何未来的用户,因为它只针对您的性能测试。通过一个真实世界的例子,概括性能答案会容易得多。
-
我不认为
Stack在这里是最快的,因为你肯定在那里分配内存,而Pool方法可能有一个已经分配的块可用。 -
我想我们必须深入研究生成的字节码
-
because it is just stack pointer increment,我怀疑内存分配和实际文件IO花费的时间比例较大,和你看到的一致。
标签: c# memory-management heap-memory allocation pooling