- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在对虚拟成员与密封成员的表现进行一些修补。
下面是我的测试代码。
输出是
virtual total 3166ms
per call virtual 3.166ns
sealed total 3931ms
per call sealed 3.931ns
[TestFixture]
public class VirtTests
{
public class ClassWithNonEmptyMethods
{
private double x;
private double y;
public virtual void VirtualMethod()
{
x++;
}
public void SealedMethod()
{
y++;
}
}
const int iterations = 1000000000;
[Test]
public void NonEmptyMethodTest()
{
var foo = new ClassWithNonEmptyMethods();
//Pre-call
foo.VirtualMethod();
foo.SealedMethod();
var virtualWatch = new Stopwatch();
virtualWatch.Start();
for (var i = 0; i < iterations; i++)
{
foo.VirtualMethod();
}
virtualWatch.Stop();
Console.WriteLine("virtual total {0}ms", virtualWatch.ElapsedMilliseconds);
Console.WriteLine("per call virtual {0}ns", ((float)virtualWatch.ElapsedMilliseconds * 1000000) / iterations);
var sealedWatch = new Stopwatch();
sealedWatch.Start();
for (var i = 0; i < iterations; i++)
{
foo.SealedMethod();
}
sealedWatch.Stop();
Console.WriteLine("sealed total {0}ms", sealedWatch.ElapsedMilliseconds);
Console.WriteLine("per call sealed {0}ns", ((float)sealedWatch.ElapsedMilliseconds * 1000000) / iterations);
}
}
最佳答案
您正在测试内存对齐对代码效率的影响。 32 位 JIT 编译器无法为 C# 代码中大小超过 32 位、long 和 double 的值类型生成高效代码。问题的根源在于 32 位 GC 堆分配器,它只 promise 在 4 的倍数的地址上对齐分配的内存。这是一个问题,您正在增加 double 数。只有当它在一个 8 的倍数的地址上对齐时,double 才是有效的。堆栈的问题也是如此,在局部变量的情况下,它在 32 位机器上也只与 4 对齐。
L1 CPU 缓存在内部组织为称为“缓存线”的块。程序读取未对齐的 double 值时会受到惩罚。尤其是跨越缓存线末端的缓存线,必须读取来自两条缓存线的字节并将其粘合在一起。未对齐在 32 位抖动中并不少见,“x”字段恰好分配在 8 的倍数的地址上的几率仅为 50-50。如果不是,则“x”和'y' 会错位,其中之一很可能跨越缓存线。您编写测试的方式会导致 VirtualMethod 或 SealedMethod 变慢。确保让他们使用相同的字段来获得可比较的结果。
代码也是如此。交换虚拟和密封测试的代码以任意更改结果。通过这种方式,我可以毫不费力地加快密封测试的速度。鉴于速度的适度差异,您可能正在查看代码对齐问题。 x64 抖动会努力插入 NOP 以使分支目标对齐,而 x86 抖动则不会。
您还应该在循环中多次运行计时测试,至少 20 次。您可能还会观察到垃圾收集器移动类对象的效果。替身之后可能会有不同的对齐方式,从而极大地改变了时间。访问像 long 或 double 这样的 64 位值类型值有 3 个不同的时序,在 8 上对齐,在一个缓存行内在 4 上对齐,以及在两个缓存行中在 4 上对齐。以快到慢的顺序。
惩罚是陡峭的,读取跨越缓存行的 double 比读取对齐的 double 大约慢三倍。也是为什么在大对象堆中分配 double[]( double 数组)的核心原因,即使它只有 1000 个元素,远远低于 80KB 的正常阈值,LOH 的对齐保证为 8。这些对齐问题在由 x64 抖动生成的代码中完全消失,堆栈和 GC 堆都具有 8 对齐。
关于.net - 这个虚方法调用如何比密封方法调用更快?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4406257/
当数据类扩展包含非抽象 open val 属性的密封类时,生成的子数据类包含与父类的私有(private)字段重复的私有(private)字段。 sealed class Foo(open val f
当封装一个.jar 文件(整个.jar,而不是特定的包)时,实际上封装了哪些包?它只是包含.class 文件的包,还是还包含父包和子包? 举个例子,假设我有一个包含单个 .class 文件 com.c
我可以很容易地为这样的密封案例类族一般派生一个编解码器: import io.circe._ import io.circe.generic.auto._ sealed trait Base case
我有一个类层次结构: class C1 { virtual object M1(); } class C2: C1 { override sealed object M1(); } class C3:
有什么区别: type MovieType = {| +blob?: string, +name: string, +url?: string |}; 和 type MovieType =
想象一个这样的 secret : apiVersion: v1 kind: Secret metadata: name: {{ include "test-cicd.fullname" . }}
因此,我的一位开发人员使用这样的函数为 Magento 电子商务网站制作自定义导航: getUrl() ?>">__('about') ?> 唯一的问题是它的输出如下: about 据我了解,如果同时
我是一名优秀的程序员,十分优秀!