Stream.Read() 性能低下
Stream.Read() is Slow Performance
使用 memorystream.Read(arr, 0, length)
为 19 Mb 文件将流转换为数组。
当 运行 它在 machine1 中大约需要 1.26 秒,在 Machine2 中大约需要 3 秒。
为什么性能会有所不同?!是不是和机器的ram使用有关,CPU?!我们需要增加 RAM 吗?!
using (var pdfContent = new MemoryStream(System.IO.File.ReadAllBytes(path)))
{
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
byte[] buffer = new byte[pdfContent.Length];
pdfContent.Read(buffer, 0, (int)pdfContent.Length);
stopwatch.Stop();
Console.WriteLine($"End Time:{stopwatch.Elapsed} ");
}
TL;DR: 1.文件操作的结果很大程度上取决于你的机器配置(类型甚至硬盘的型号在这种情况下是最关键的测试)。 2. 你应该分块读取文件。
让我们仔细看看这个例子。我准备了一个 21042116 字节的测试文本文件,即 21Mb,创建一个新的控制台应用程序并添加基准库:BenchmarkDotNet:
using System;
using System.Diagnostics;
using System.IO;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Jobs;
using BenchmarkDotNet.Running;
namespace stream_perf
{
[SimpleJob(RuntimeMoniker.NetCoreApp50)]
[RPlotExporter]
public class StreamBenchmarks
{
[Benchmark]
public void Whosebug()
{
using (var pdfContent = new MemoryStream(System.IO.File.ReadAllBytes("payload.txt")))
{
byte[] buffer = new byte[pdfContent.Length];
pdfContent.Read(buffer, 0, (int)pdfContent.Length);
}
}
}
class Program
{
static void Main(string[] args)
{
var summary = BenchmarkRunner.Run<StreamBenchmarks>();
}
}
}
使用控制台 运行 两个命令:
dotnet build -c release
dotnet run -c release
这给了我以下结果:
BenchmarkDotNet=v0.12.1, OS=Windows 10.0.19042
Intel Core i5-8300H CPU 2.30GHz (Coffee Lake), 1 CPU, 8 logical and 4 physical cores
.NET Core SDK=5.0.103
[Host] : .NET Core 5.0.3 (CoreCLR 5.0.321.7212, CoreFX 5.0.321.7212), X64 RyuJIT
.NET Core 5.0 : .NET Core 5.0.3 (CoreCLR 5.0.321.7212, CoreFX 5.0.321.7212), X64 RyuJIT
Job=.NET Core 5.0 Runtime=.NET Core 5.0
| Method | Mean | Error | StdDev |
|-------------- |---------:|---------:|---------:|
| Whosebug | 24.24 ms | 0.378 ms | 0.353 ms |
正如您在我的机器上看到的那样,速度非常快。
但是它够快吗?不,它不够快,因为我们两次读取该文件数据,第一次在这里读取文件:System.IO.File.ReadAllBytes("payload.txt")
,第二次在这里读取文件:pdfContent.Read(buffer, 0, (int)pdfContent.Length);
。所以我在我的基准测试中添加了以下方法:
[Benchmark]
public void ReadChunked()
{
int totalBytes = 0;
int readBytes = 0;
using (var pdfStream = new System.IO.FileStream("payload.txt", FileMode.Open))
{
byte[] buffer = new byte[4096];
while ((readBytes = pdfStream.Read(buffer)) != 0) {
// do something with buffer
totalBytes += readBytes;
}
}
}
在这种新方法中,我们按块读取文件,这给了我们一些优势:
- 我们读一次文件
- 我们不需要在 RAM 中分配等于文件大小的缓冲区
让我们看看基准:
BenchmarkDotNet=v0.12.1, OS=Windows 10.0.19042
Intel Core i5-8300H CPU 2.30GHz (Coffee Lake), 1 CPU, 8 logical and 4 physical cores
.NET Core SDK=5.0.103
[Host] : .NET Core 5.0.3 (CoreCLR 5.0.321.7212, CoreFX 5.0.321.7212), X64 RyuJIT
.NET Core 5.0 : .NET Core 5.0.3 (CoreCLR 5.0.321.7212, CoreFX 5.0.321.7212), X64 RyuJIT
Job=.NET Core 5.0 Runtime=.NET Core 5.0
| Method | Mean | Error | StdDev |
|-------------- |---------:|---------:|---------:|
| Whosebug | 23.85 ms | 0.149 ms | 0.132 ms |
| ReadChunked | 18.68 ms | 0.076 ms | 0.071 ms |
新方法速度提高了 21%
使用 memorystream.Read(arr, 0, length)
为 19 Mb 文件将流转换为数组。
当 运行 它在 machine1 中大约需要 1.26 秒,在 Machine2 中大约需要 3 秒。
为什么性能会有所不同?!是不是和机器的ram使用有关,CPU?!我们需要增加 RAM 吗?!
using (var pdfContent = new MemoryStream(System.IO.File.ReadAllBytes(path)))
{
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
byte[] buffer = new byte[pdfContent.Length];
pdfContent.Read(buffer, 0, (int)pdfContent.Length);
stopwatch.Stop();
Console.WriteLine($"End Time:{stopwatch.Elapsed} ");
}
TL;DR: 1.文件操作的结果很大程度上取决于你的机器配置(类型甚至硬盘的型号在这种情况下是最关键的测试)。 2. 你应该分块读取文件。
让我们仔细看看这个例子。我准备了一个 21042116 字节的测试文本文件,即 21Mb,创建一个新的控制台应用程序并添加基准库:BenchmarkDotNet:
using System;
using System.Diagnostics;
using System.IO;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Jobs;
using BenchmarkDotNet.Running;
namespace stream_perf
{
[SimpleJob(RuntimeMoniker.NetCoreApp50)]
[RPlotExporter]
public class StreamBenchmarks
{
[Benchmark]
public void Whosebug()
{
using (var pdfContent = new MemoryStream(System.IO.File.ReadAllBytes("payload.txt")))
{
byte[] buffer = new byte[pdfContent.Length];
pdfContent.Read(buffer, 0, (int)pdfContent.Length);
}
}
}
class Program
{
static void Main(string[] args)
{
var summary = BenchmarkRunner.Run<StreamBenchmarks>();
}
}
}
使用控制台 运行 两个命令:
dotnet build -c release
dotnet run -c release
这给了我以下结果:
BenchmarkDotNet=v0.12.1, OS=Windows 10.0.19042
Intel Core i5-8300H CPU 2.30GHz (Coffee Lake), 1 CPU, 8 logical and 4 physical cores
.NET Core SDK=5.0.103
[Host] : .NET Core 5.0.3 (CoreCLR 5.0.321.7212, CoreFX 5.0.321.7212), X64 RyuJIT
.NET Core 5.0 : .NET Core 5.0.3 (CoreCLR 5.0.321.7212, CoreFX 5.0.321.7212), X64 RyuJIT
Job=.NET Core 5.0 Runtime=.NET Core 5.0
| Method | Mean | Error | StdDev |
|-------------- |---------:|---------:|---------:|
| Whosebug | 24.24 ms | 0.378 ms | 0.353 ms |
正如您在我的机器上看到的那样,速度非常快。
但是它够快吗?不,它不够快,因为我们两次读取该文件数据,第一次在这里读取文件:System.IO.File.ReadAllBytes("payload.txt")
,第二次在这里读取文件:pdfContent.Read(buffer, 0, (int)pdfContent.Length);
。所以我在我的基准测试中添加了以下方法:
[Benchmark]
public void ReadChunked()
{
int totalBytes = 0;
int readBytes = 0;
using (var pdfStream = new System.IO.FileStream("payload.txt", FileMode.Open))
{
byte[] buffer = new byte[4096];
while ((readBytes = pdfStream.Read(buffer)) != 0) {
// do something with buffer
totalBytes += readBytes;
}
}
}
在这种新方法中,我们按块读取文件,这给了我们一些优势:
- 我们读一次文件
- 我们不需要在 RAM 中分配等于文件大小的缓冲区
让我们看看基准:
BenchmarkDotNet=v0.12.1, OS=Windows 10.0.19042
Intel Core i5-8300H CPU 2.30GHz (Coffee Lake), 1 CPU, 8 logical and 4 physical cores
.NET Core SDK=5.0.103
[Host] : .NET Core 5.0.3 (CoreCLR 5.0.321.7212, CoreFX 5.0.321.7212), X64 RyuJIT
.NET Core 5.0 : .NET Core 5.0.3 (CoreCLR 5.0.321.7212, CoreFX 5.0.321.7212), X64 RyuJIT
Job=.NET Core 5.0 Runtime=.NET Core 5.0
| Method | Mean | Error | StdDev |
|-------------- |---------:|---------:|---------:|
| Whosebug | 23.85 ms | 0.149 ms | 0.132 ms |
| ReadChunked | 18.68 ms | 0.076 ms | 0.071 ms |
新方法速度提高了 21%