Mar*_*ger 0 .net c# performance
我从 .NET 6.0 更改为 .NET 7.0,发现一些性能关键型任务所需的时间几乎是 .NET 6.0 的两倍(没有进行任何代码更改!)。
我能够得出一个简单的例子,它至少显示了一个有趣的效果:
using System;
using System.Collections.Generic;
using System.Diagnostics;
public readonly struct MyStruct {
public int Parent { get; }
public int Child { get; }
public MyStruct(int p, int c) {
Parent = p;
Child = c;
}
}
static class MyProgram {
static int Main(string[] args) {
Stopwatch stopwatch = new Stopwatch();
List<MyStruct> list = new() { new(1, 1)};
stopwatch.Start();
for (int j = 0; j < 500_000; ++j) {
for (int i = 0; i < 1000; ++i) {
int p = list[0].Parent;
int c = list[0].Child;
}
}
Console.WriteLine(stopwatch.ElapsedMilliseconds);
return 0;
}
}
Run Code Online (Sandbox Code Playgroud)
对于 .NET 6.0,这大约需要 240 毫秒,而对于 .NET 7.0,则需要 450 毫秒(大约长 41%)。
据我所知,MSIL 代码是等效的,所以看起来 JIT 编译器在 .NET 7.0 中做了一些严重不同的事情?
任何人都可以确认这一点,或者其他人在切换到 .NET 7.0 时是否会遇到性能下降(顺便说一下,对于 .NET 8.0 来说是一样的)?
这种行为非常脆弱:创建一个结构体类,添加另一个属性,将嵌套循环组合成一个等等,并且两个版本的性能几乎相同。
所以它表明 .NET 6.0 做了一些优化(内联?),而在 .NET 7.0 中不再进行这些优化。
你的测试有问题。仅诉诸 Stopwatch 类并在调试模式下运行不会给您带来有意义的结果。还有很多事情要做,比如预热 JITer。使用BenchmarkDotNet等适当的基准测试工具表明 .NET 7 在这方面实际上更快一些,并且内存效率更高。
| 方法 | 工作 | 运行 | 意思是 | 错误 | 标准差 | 已分配 |
|---|---|---|---|---|---|---|
| 我的基准测试 | .NET 6.0 | .NET 6.0 | 366.3 毫秒 | 7.24 毫秒 | 9.15 毫秒 | 728乙 |
| 我的基准测试 | .NET 7.0 | .NET 7.0 | 320.0 毫秒 | 6.09 毫秒 | 5.40 毫秒 | 388 乙 |
MyBenchmarks.cs
using BenchmarkDotNet.Attributes;
namespace HelloConsole;
[SimpleJob(BenchmarkDotNet.Jobs.RuntimeMoniker.Net60)]
[SimpleJob(BenchmarkDotNet.Jobs.RuntimeMoniker.Net70)]
[MemoryDiagnoser]
public class MyBenchmarks
{
public readonly struct MyStruct
{
public int Parent { get; }
public int Child { get; }
public MyStruct(int p, int c)
{
Parent = p;
Child = c;
}
}
[Benchmark]
public void MyBenchmark()
{
List<MyStruct> list = new() { new(1, 1) };
for (int j = 0; j < 500_000; ++j)
{
for (int i = 0; i < 1000; ++i)
{
int p = list[0].Parent;
int c = list[0].Child;
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
程序.cs
using BenchmarkDotNet.Running;
using HelloConsole;
var summary = BenchmarkRunner.Run<MyBenchmarks>();
Run Code Online (Sandbox Code Playgroud)
项目文件(.csproj)
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFrameworks>net6.0;net7.0</TargetFrameworks>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="BenchmarkDotNet" Version="0.13.5" />
</ItemGroup>
</Project>
Run Code Online (Sandbox Code Playgroud)