gpt4 book ai didi

c# - Func 与自定义委托(delegate)性能

转载 作者:行者123 更新时间:2023-12-03 14:50:02 25 4
gpt4 key购买 nike

我正在处理一些性能非常关键的代码,并且发现使用委托(delegate)调用匿名方法比通过 Func 委托(delegate)调用相同的代码执行得更差。

public class DelegateTests
{
public delegate int GetValueDelegate(string test);

private Func<string, int> getValueFunc;

private GetValueDelegate getValueDelegate;

public DelegateTests()
{
getValueDelegate = (s) => 42;
getValueFunc = (s) => 42;
}

[Benchmark]
public int CallWithDelegate()
{
return getValueDelegate.Invoke("TEST");
}

[Benchmark]
public int CallWithFunc()
{
return getValueFunc.Invoke("TEST");
}
}
BenchmarkDotNet给出:
// * Summary *

BenchmarkDotNet=v0.10.4, OS=Windows 10.0.14393
Processor=Intel Core i7-4770HQ CPU 2.20GHz (Haswell), ProcessorCount=2
Frequency=10000000 Hz, Resolution=100.0000 ns, Timer=UNKNOWN
[Host] : Clr 4.0.30319.42000, 32bit LegacyJIT-v4.6.1637.0
RyuJitX64 : Clr 4.0.30319.42000, 64bit RyuJIT-v4.6.1637.0

Job=RyuJitX64 Jit=RyuJit Platform=X64

Method | Mean | Error | StdDev |
----------------- |----------:|----------:|----------:|
CallWithDelegate | 0.9926 ns | 0.0559 ns | 0.0783 ns |
CallWithFunc | 0.8763 ns | 0.0168 ns | 0.0131 ns |

// * Hints *
Outliers
DelegateTests.CallWithFunc: RyuJitX64 -&gt; 3 outliers were removed

// * Legends *
Mean : Arithmetic mean of all measurements
Error : Half of 99.9% confidence interval
StdDev : Standard deviation of all measurements

// ***** BenchmarkRunner: End *****

如我们所见,使用 Func 调用函数委托(delegate)比使用 GetValueDelegate 调用函数更快。 .
我试图找到证据说明它为什么会这样。
查看 JIT 优化的机器码
    26:             return getValueDelegate.Invoke(&quot;TEST&quot;);
00E105C0 8B 49 08 mov ecx,dword ptr [ecx+8]
00E105C3 8B 15 C4 22 71 03 mov edx,dword ptr ds:[37122C4h]
00E105C9 8B 41 0C mov eax,dword ptr [ecx+0Ch]
00E105CC 8B 49 04 mov ecx,dword ptr [ecx+4]
00E105CF FF D0 call eax
00E105D1 C3 ret

相比
    32:             return getValueFunc.Invoke(&quot;TEST&quot;);
00E10608 8B 49 04 mov ecx,dword ptr [ecx+4]
00E1060B 8B 15 C4 22 71 03 mov edx,dword ptr ds:[37122C4h]
00E10611 8B 41 0C mov eax,dword ptr [ecx+0Ch]
00E10614 8B 49 04 mov ecx,dword ptr [ecx+4]
00E10617 FF D0 call eax
00E10619 C3 ret

他们看起来非常相似。
我开始认为这可能是两个代表的 Invoke 方法内部的差异。它们都派生自 MulticastDelegate,这是 CLR 上所有代表的要求。
为什么一个比另一个快?

更新

以下是使用 LegacyJitx86 的数字。
请注意,我只是对为什么存在差异感兴趣。
顺便说一句,交换序列或变量顺序不会影响结果
// * Summary *

BenchmarkDotNet=v0.10.4, OS=Windows 10.0.14393
Processor=Intel Core i7-4770HQ CPU 2.20GHz (Haswell), ProcessorCount=2
Frequency=10000000 Hz, Resolution=100.0000 ns, Timer=UNKNOWN
[Host] : Clr 4.0.30319.42000, 32bit LegacyJIT-v4.6.1637.0
LegacyJitX86 : Clr 4.0.30319.42000, 32bit LegacyJIT-v4.6.1637.0

Job=LegacyJitX86 Jit=LegacyJit Platform=X86
Runtime=Clr

Method | Mean | Error | StdDev |
----------------- |----------:|----------:|----------:|
CallWithDelegate | 2.3385 ns | 0.0361 ns | 0.0320 ns |
CallWithFunc | 2.0144 ns | 0.0410 ns | 0.0384 ns |

// * Hints *
Outliers
DelegateTests.CallWithDelegate: LegacyJitX86 -&gt; 1 outlier was removed

// * Legends *
Mean : Arithmetic mean of all measurements
Error : Half of 99.9% confidence interval
StdDev : Standard deviation of all measurements

// ***** BenchmarkRunner: End *****

最佳答案

用我机器上所有东西的当前版本运行它们,我发现没有一致的赢家。

运行#1

在本次运行中,CallWithFunc的平均时间加上误差是 CallWithDelegate 的 99%的平均时间减去错误,所以我觉得可能会有一些旧行为的残余......


BenchmarkDotNet=v0.12.0, OS=Windows 10.0.18363
Intel Core i7-6850K CPU 3.60GHz (Skylake), 1 CPU, 12 logical and 6 physical cores
.NET Core SDK=3.1.101
[Host] : .NET Core 3.1.1 (CoreCLR 4.700.19.60701, CoreFX 4.700.19.60801), X64 RyuJIT
DefaultJob : .NET Core 3.1.1 (CoreCLR 4.700.19.60701, CoreFX 4.700.19.60801), X64 RyuJIT


|           Method |     Mean |     Error |    StdDev |
|----------------- |---------:|----------:|----------:|
| CallWithDelegate | 1.103 ns | 0.0024 ns | 0.0019 ns |
| CallWithFunc | 1.090 ns | 0.0050 ns | 0.0044 ns |

运行#2

但是当我再次运行它时,获胜者实际上翻转了,所以我的猜测是,如果有一个有利于其中一个的因素,那么它可能是非常具体的。

例如,可能更快的回调恰好与其他一些重要的东西位于同一缓存行上,而较慢的回调可能是唯一将回调保留在 CPU 缓存中的东西(在这种情况下,更改字段的顺序 [StructLayout(LayoutKind.Sequential)] 标记类(class)可能会揭示一些东西)。

BenchmarkDotNet=v0.12.0, OS=Windows 10.0.18363
Intel Core i7-6850K CPU 3.60GHz (Skylake), 1 CPU, 12 logical and 6 physical cores
.NET Core SDK=3.1.101
[Host] : .NET Core 3.1.1 (CoreCLR 4.700.19.60701, CoreFX 4.700.19.60801), X64 RyuJIT
DefaultJob : .NET Core 3.1.1 (CoreCLR 4.700.19.60701, CoreFX 4.700.19.60801), X64 RyuJIT

|           Method |     Mean |     Error |    StdDev |
|----------------- |---------:|----------:|----------:|
| CallWithDelegate | 1.062 ns | 0.0036 ns | 0.0030 ns |
| CallWithFunc | 1.094 ns | 0.0039 ns | 0.0034 ns |

关于c# - Func 与自定义委托(delegate)性能,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43769065/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com