gpt4 book ai didi

c# - 为什么 typeA == typeB 比 type == typeof(Type B) 慢?

转载 作者:可可西里 更新时间:2023-11-01 07:46:27 25 4
gpt4 key购买 nike

我最近一直在优化/对一些代码进行基准测试并遇到了这个方法:

public void SomeMethod(Type messageType)
{
if (messageType == typeof(BroadcastMessage))
{
// ...
}
else if (messageType == typeof(DirectMessage))
{
// ...
}
else if (messageType == typeof(ClientListRequest))
{
// ...
}
}

这是从其他地方的性能关键循环调用的,所以我很自然地假设所有这些 typeof(...) 调用都增加了不必要的开销(我知道这是一种微优化)并且可以移动到类中的私有(private)字段。 (我知道有更好的方法来重构这段代码,但是,我仍然想知道这里发生了什么。)

根据我的基准测试,情况完全不是这样(使用 BenchmarkDotNet )。

[DisassemblyDiagnoser(printAsm: true, printSource: true)]
[RyuJitX64Job]
public class Tests
{
private Type a = typeof(string);
private Type b = typeof(int);

[Benchmark]
public bool F1()
{
return a == typeof(int);
}

[Benchmark]
public bool F2()
{
return a == b;
}
}

我机器上的结果(Window 10 x64、.NET 4.7.2、RyuJIT、发布版本):

编译成ASM的函数:

F1

mov     rcx,offset mscorlib_ni+0x729e10
call clr!InstallCustomModule+0x2320
mov rcx,qword ptr [rsp+30h]
cmp qword ptr [rcx+8],rax
sete al
movzx eax,al

F2

mov     qword ptr [rsp+30h],rcx
mov rcx,qword ptr [rcx+8]
mov rdx,qword ptr [rsp+30h]
mov rdx,qword ptr [rdx+10h]
call System.Type.op_Equality(System.Type, System.Type)
movzx eax,al

我不知道如何解释 ASM,因此无法理解这里发生的事情的重要性。简而言之,为什么 F1 更快?

最佳答案

您发布的程序集表明 mjwills 的评论正如预期的那样是正确的。正如链接文章所指出的,抖动对于某些比较可能很聪明,这就是其中之一。

让我们看看您的第一个片段:

mov     rcx,offset mscorlib_ni+0x729e10

rcx 是调用成员函数的“this 指针”。在这种情况下,“this 指针”将是某个 CLR 预分配对象的地址,具体是什么我不知道。

call    clr!InstallCustomModule+0x2320

现在我们调用那个对象的一些成员函数;我不知道是什么。您拥有调试信息的最近 公共(public)函数是 InstallCustomModule,但很明显我们没有在这里调用 InstallCustomModule;我们正在调用距 InstallCustomModule 0x2320 字节的函数。

看看 InstallCustomModule+0x2320 的代码做了什么会很有趣。

无论如何,我们进行调用,返回值进入 rax。继续:

mov     rcx,qword ptr [rsp+30h]
cmp qword ptr [rcx+8],rax

这看起来像是从 this 中获取 a 的值,并将它与函数返回的任何值进行比较。

其余代码非常普通:将比较的 bool 结果移入返回寄存器。

简而言之,第一个片段相当于:

return ReferenceEquals(SomeConstantObject.SomeUnknownFunction(), this.a);

显然这里有根据的猜测是常量对象和未知函数是具有特殊用途的助手,可以快速获取常用类型对象,如 typeof(int)。

第二个有根据的猜测是,抖动自行决定模式“将 Type 类型的字段与 typeof(something) 进行比较”最好作为对象之间的直接引用比较。

现在您可以亲眼看到第二个片段的作用。它只是:

return Type.op_Equality(this.a, this.b);

它所做的只是调用一个辅助方法来比较两种类型的值相等性。请记住,CLR 不保证所有等效类型对象的引用相等

现在应该清楚为什么第一个片段更快了。 抖动对第一个片段的了解要多得多。例如,它知道 typeof(int) 将始终返回相同的引用,因此您可以进行廉价的引用比较。它知道 typeof(int) 永远不会为 null。它知道 typeof(int) 的确切类型——记住,Type 不是密封的;您可以创建自己的 Type 对象。

在第二个片段中,抖动只知道它有两个 Type 类型的操作数。它不知道它们的运行时类型,也不知道它们的无效性;就其所知,您自己对 Type 进行了子类化,并组成了两个引用不相等但值相等的实例。它必须回落到最保守的位置并调用一个开始在列表中向下移动的辅助方法:它们都是空的吗?其中一个为空,另一个为非空?他们引用相等吗?等等。

看起来缺乏这些知识会让您付出巨大的代价……半纳秒。我不会为此担心。

关于c# - 为什么 typeA == typeB 比 type == typeof(Type B) 慢?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54874400/

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