Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/20.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
.net 密封类真的提供性能优势吗?_.net_Optimization_Frameworks_Performance - Fatal编程技术网

.net 密封类真的提供性能优势吗?

.net 密封类真的提供性能优势吗?,.net,optimization,frameworks,performance,.net,Optimization,Frameworks,Performance,我遇到了很多优化技巧,它们说你应该将你的类标记为密封的,以获得额外的性能优势 我运行了一些测试来检查性能差异,但没有发现任何差异。我做错什么了吗?我是否错过了密封类将提供更好结果的情况 有人运行测试并看到了差异吗 帮助我了解:)抖动有时会对密封类中的方法使用非虚拟调用,因为它们无法进一步扩展 关于调用类型、虚拟/非虚拟,有很多复杂的规则,我不知道所有这些规则,所以我无法为您概括这些规则,但是如果您搜索密封类和虚拟方法,您可能会找到一些关于这个主题的文章 请注意,从这一级别的优化中获得的任何性能优

我遇到了很多优化技巧,它们说你应该将你的类标记为密封的,以获得额外的性能优势

我运行了一些测试来检查性能差异,但没有发现任何差异。我做错什么了吗?我是否错过了密封类将提供更好结果的情况

有人运行测试并看到了差异吗


帮助我了解:)

抖动有时会对密封类中的方法使用非虚拟调用,因为它们无法进一步扩展

关于调用类型、虚拟/非虚拟,有很多复杂的规则,我不知道所有这些规则,所以我无法为您概括这些规则,但是如果您搜索密封类和虚拟方法,您可能会找到一些关于这个主题的文章

请注意,从这一级别的优化中获得的任何性能优势都应视为最后手段,在代码级别优化之前,始终在算法级别进行优化

这里有一个链接提到这一点:

密封类应该提供性能改进。由于无法派生密封类,因此任何虚拟成员都可以转换为非虚拟成员

当然,我们谈论的是非常小的收益。我不会为了提高性能而将一个类标记为密封的,除非分析表明它是一个问题。

我讨厌封闭的课堂。即使性能优势令人震惊(我对此表示怀疑),它们也会通过阻止通过继承进行重用而破坏面向对象模型。例如,Thread类是密封的。虽然我可以看到人们可能希望线程尽可能地高效,但我也可以想象这样的场景:能够对线程进行子类化将带来巨大的好处。 类作者,如果您出于“性能”原因必须密封类,请至少提供一个接口,这样我们就不必包装和替换您忘记的功能

示例:必须包装Thread类,因为Thread是密封的,并且没有IThread接口;SafeThread会自动在线程上捕获未处理的异常,Thread类中完全缺少这一点。[否,未处理的异常事件不会在次线程中拾取未处理的异常]


答案是否定的,密封类的性能并不比非密封类好

问题归结为呼叫与呼叫之间的冲突
Call
callvirt
快,而且
callvirt
主要用于不知道对象是否已被子类化的情况。因此人们认为,如果你密封一个类,所有的操作码都会从
calvirts
变为
calls
,并且会更快

不幸的是,
callvirt
还做了其他一些事情,比如检查空引用。这意味着,即使类被密封,引用也可能仍然为null,因此需要
callvirt
。您可以绕过这个问题(无需密封类),但它变得有点毫无意义

结构使用
调用
,因为它们不能被子类化,并且从不为null

有关更多信息,请参见此问题:


将类标记为密封的应该不会对性能产生影响

在某些情况下,
csc
可能必须发出
callvirt
操作码,而不是
call
操作码。然而,这些病例似乎很少见

在我看来,JIT应该能够为
callvirt
发出与
call
相同的非虚拟函数调用,如果它知道类没有任何子类的话。如果只存在该方法的一个实现,那么从vtable加载其地址没有意义,只需直接调用该实现即可。因此,JIT甚至可以内联函数

这对JIT来说有点冒险,因为如果以后加载子类,JIT将不得不扔掉该机器代码并再次编译代码,发出真正的虚拟调用。我猜这在实践中并不经常发生


(是的,虚拟机设计人员确实积极追求这些微小的性能胜利。)

运行此代码,您将看到密封类的速度提高了2倍:

class Program
{
    static void Main(string[] args)
    {
        Console.ReadLine();

        var watch = new Stopwatch();
        watch.Start();
        for (int i = 0; i < 10000000; i++)
        {
            new SealedClass().GetName();
        }
        watch.Stop();
        Console.WriteLine("Sealed class : {0}", watch.Elapsed.ToString());

        watch.Start();
        for (int i = 0; i < 10000000; i++)
        {
            new NonSealedClass().GetName();
        }
        watch.Stop();
        Console.WriteLine("NonSealed class : {0}", watch.Elapsed.ToString());

        Console.ReadKey();
    }
}

sealed class SealedClass
{
    public string GetName()
    {
        return "SealedClass";
    }
}

class NonSealedClass
{
    public string GetName()
    {
        return "NonSealedClass";
    }
}
类程序
{
静态void Main(字符串[]参数)
{
Console.ReadLine();
var watch=新秒表();
watch.Start();
对于(int i=0;i<10000000;i++)
{
新建SealedClass().GetName();
}
看,停;
WriteLine(“密封类:{0}”,watch.appeased.ToString());
watch.Start();
对于(int i=0;i<10000000;i++)
{
新的非密封类().GetName();
}
看,停;
WriteLine(“非密封类:{0}”,watch.appeased.ToString());
Console.ReadKey();
}
}
密封等级密封等级
{
公共字符串GetName()
{
返回“SealedClass”;
}
}
类非密封类
{
公共字符串GetName()
{
返回“非密封类”;
}
}
输出: 密封等级:00:00:00.1897568 非密封类:00:00:38 26268 < /P> < P>我认为“密封”类是正常情况,我总是有理由省略“密封”关键字。 对我来说,最重要的原因是:

a) 更好的编译时检查(转换到未实现的接口将在编译时检测,而不仅仅是在运行时)

最主要的原因是:

b) 这样就不可能滥用我的课程


我希望微软能将标准“密封”,而不是“未密封”。

正如我所知,性能优势无法保证。但是,在某些特定条件下,使用密封方法有机会降低性能惩罚。(sealed类使所有方法都被密封。)

但这取决于编译器实现和exec
// Value of `v` is unknown,
// and can be resolved only at runtime.
// CPU cannot know which code to prefetch.
// Therefore, just prefetch any one of a() or b().
// This is *speculative execution*.
int v = random();
if (v==1) a();
else b();
public class NormalClass {
    public void WriteIt(string x) {
        Console.WriteLine("NormalClass");
        Console.WriteLine(x);
    }
}

public sealed class SealedClass {
    public void WriteIt(string x) {
        Console.WriteLine("SealedClass");
        Console.WriteLine(x);
    }
}

public static void CallNormal() {
    var n = new NormalClass();
    n.WriteIt("a string");
}

public static void CallSealed() {
    var n = new SealedClass();
    n.WriteIt("a string");
}
L_0000: newobj instance void <NormalClass or SealedClass>::.ctor()
L_0005: stloc.0 
L_0006: ldloc.0 
L_0007: ldstr "a string"
L_000c: callvirt instance void <NormalClass or SealedClass>::WriteIt(string)
L_0011: ret 
//            var n = new NormalClass();
00000000  push        ebp 
00000001  mov         ebp,esp 
00000003  sub         esp,8 
00000006  cmp         dword ptr ds:[00585314h],0 
0000000d  je          00000014 
0000000f  call        70032C33 
00000014  xor         edx,edx 
00000016  mov         dword ptr [ebp-4],edx 
00000019  mov         ecx,588230h 
0000001e  call        FFEEEBC0 
00000023  mov         dword ptr [ebp-8],eax 
00000026  mov         ecx,dword ptr [ebp-8] 
00000029  call        dword ptr ds:[00588260h] 
0000002f  mov         eax,dword ptr [ebp-8] 
00000032  mov         dword ptr [ebp-4],eax 
//            n.WriteIt("a string");
00000035  mov         edx,dword ptr ds:[033220DCh] 
0000003b  mov         ecx,dword ptr [ebp-4] 
0000003e  cmp         dword ptr [ecx],ecx 
00000040  call        dword ptr ds:[0058827Ch] 
//        }
00000046  nop 
00000047  mov         esp,ebp 
00000049  pop         ebp 
0000004a  ret 
Normal JIT generated code
Begin 003c00b0, size 39
003c00b0 55              push    ebp
003c00b1 8bec            mov     ebp,esp
003c00b3 b994391800      mov     ecx,183994h (MT: ScratchConsoleApplicationFX4.NormalClass)
003c00b8 e8631fdbff      call    00172020 (JitHelp: CORINFO_HELP_NEWSFAST)
003c00bd e80e70106f      call    mscorlib_ni+0x2570d0 (6f4c70d0) (System.Console.get_Out(), mdToken: 060008fd)
003c00c2 8bc8            mov     ecx,eax
003c00c4 8b1530203003    mov     edx,dword ptr ds:[3302030h] ("NormalClass")
003c00ca 8b01            mov     eax,dword ptr [ecx]
003c00cc 8b403c          mov     eax,dword ptr [eax+3Ch]
003c00cf ff5010          call    dword ptr [eax+10h]
003c00d2 e8f96f106f      call    mscorlib_ni+0x2570d0 (6f4c70d0) (System.Console.get_Out(), mdToken: 060008fd)
003c00d7 8bc8            mov     ecx,eax
003c00d9 8b1534203003    mov     edx,dword ptr ds:[3302034h] ("a string")
003c00df 8b01            mov     eax,dword ptr [ecx]
003c00e1 8b403c          mov     eax,dword ptr [eax+3Ch]
003c00e4 ff5010          call    dword ptr [eax+10h]
003c00e7 5d              pop     ebp
003c00e8 c3              ret
Normal JIT generated code
Begin 003c0100, size 39
003c0100 55              push    ebp
003c0101 8bec            mov     ebp,esp
003c0103 b90c3a1800      mov     ecx,183A0Ch (MT: ScratchConsoleApplicationFX4.SealedClass)
003c0108 e8131fdbff      call    00172020 (JitHelp: CORINFO_HELP_NEWSFAST)
003c010d e8be6f106f      call    mscorlib_ni+0x2570d0 (6f4c70d0) (System.Console.get_Out(), mdToken: 060008fd)
003c0112 8bc8            mov     ecx,eax
003c0114 8b1538203003    mov     edx,dword ptr ds:[3302038h] ("SealedClass")
003c011a 8b01            mov     eax,dword ptr [ecx]
003c011c 8b403c          mov     eax,dword ptr [eax+3Ch]
003c011f ff5010          call    dword ptr [eax+10h]
003c0122 e8a96f106f      call    mscorlib_ni+0x2570d0 (6f4c70d0) (System.Console.get_Out(), mdToken: 060008fd)
003c0127 8bc8            mov     ecx,eax
003c0129 8b1534203003    mov     edx,dword ptr ds:[3302034h] ("a string")
003c012f 8b01            mov     eax,dword ptr [ecx]
003c0131 8b403c          mov     eax,dword ptr [eax+3Ch]
003c0134 ff5010          call    dword ptr [eax+10h]
003c0137 5d              pop     ebp
003c0138 c3              ret
public sealed class Sealed
{
    public string Message { get; set; }
    public void DoStuff() { }
}
public class Derived : Base
{
    public sealed override void DoStuff() { }
}
public class Base
{
    public string Message { get; set; }
    public virtual void DoStuff() { }
}
static void Main()
{
    Sealed sealedClass = new Sealed();
    sealedClass.DoStuff();
    Derived derivedClass = new Derived();
    derivedClass.DoStuff();
    Base BaseClass = new Base();
    BaseClass.DoStuff();
}
.method private hidebysig static void  Main() cil managed
{
  .entrypoint
  // Code size       41 (0x29)
  .maxstack  8
  IL_0000:  newobj     instance void ConsoleApp1.Program/Sealed::.ctor()
  IL_0005:  callvirt   instance void ConsoleApp1.Program/Sealed::DoStuff()
  IL_000a:  newobj     instance void ConsoleApp1.Program/Derived::.ctor()
  IL_000f:  callvirt   instance void ConsoleApp1.Program/Base::DoStuff()
  IL_0014:  newobj     instance void ConsoleApp1.Program/Base::.ctor()
  IL_0019:  callvirt   instance void ConsoleApp1.Program/Base::DoStuff()
  IL_0028:  ret
} // end of method Program::Main
--- C:\Users\Ivan Porta\source\repos\ConsoleApp1\Program.cs --------------------
        {
0066084A  in          al,dx  
0066084B  push        edi  
0066084C  push        esi  
0066084D  push        ebx  
0066084E  sub         esp,4Ch  
00660851  lea         edi,[ebp-58h]  
00660854  mov         ecx,13h  
00660859  xor         eax,eax  
0066085B  rep stos    dword ptr es:[edi]  
0066085D  cmp         dword ptr ds:[5842F0h],0  
00660864  je          0066086B  
00660866  call        744CFAD0  
0066086B  xor         edx,edx  
0066086D  mov         dword ptr [ebp-3Ch],edx  
00660870  xor         edx,edx  
00660872  mov         dword ptr [ebp-48h],edx  
00660875  xor         edx,edx  
00660877  mov         dword ptr [ebp-44h],edx  
0066087A  xor         edx,edx  
0066087C  mov         dword ptr [ebp-40h],edx  
0066087F  nop  
            Sealed sealedClass = new Sealed();
00660880  mov         ecx,584E1Ch  
00660885  call        005730F4  
0066088A  mov         dword ptr [ebp-4Ch],eax  
0066088D  mov         ecx,dword ptr [ebp-4Ch]  
00660890  call        00660468  
00660895  mov         eax,dword ptr [ebp-4Ch]  
00660898  mov         dword ptr [ebp-3Ch],eax  
            sealedClass.DoStuff();
0066089B  mov         ecx,dword ptr [ebp-3Ch]  
0066089E  cmp         dword ptr [ecx],ecx  
006608A0  call        00660460  
006608A5  nop  
            Derived derivedClass = new Derived();
006608A6  mov         ecx,584F3Ch  
006608AB  call        005730F4  
006608B0  mov         dword ptr [ebp-50h],eax  
006608B3  mov         ecx,dword ptr [ebp-50h]  
006608B6  call        006604A8  
006608BB  mov         eax,dword ptr [ebp-50h]  
006608BE  mov         dword ptr [ebp-40h],eax  
            derivedClass.DoStuff();
006608C1  mov         ecx,dword ptr [ebp-40h]  
006608C4  mov         eax,dword ptr [ecx]  
006608C6  mov         eax,dword ptr [eax+28h]  
006608C9  call        dword ptr [eax+10h]  
006608CC  nop  
            Base BaseClass = new Base();
006608CD  mov         ecx,584EC0h  
006608D2  call        005730F4  
006608D7  mov         dword ptr [ebp-54h],eax  
006608DA  mov         ecx,dword ptr [ebp-54h]  
006608DD  call        00660490  
006608E2  mov         eax,dword ptr [ebp-54h]  
006608E5  mov         dword ptr [ebp-44h],eax  
            BaseClass.DoStuff();
006608E8  mov         ecx,dword ptr [ebp-44h]  
006608EB  mov         eax,dword ptr [ecx]  
006608ED  mov         eax,dword ptr [eax+28h]  
006608F0  call        dword ptr [eax+10h]  
006608F3  nop  
        }
0066091A  nop  
0066091B  lea         esp,[ebp-0Ch]  
0066091E  pop         ebx  
0066091F  pop         esi  
00660920  pop         edi  
00660921  pop         ebp  

00660922  ret