锁定 .NET 与 Java 的成本

2022-09-01 14:31:21

我正在玩Disruptor框架及其用于.NET平台的端口,并发现了一个有趣的案例。可能是我完全错过了一些东西,所以我正在寻找全能社区的帮助。

        long iterations = 500*1000*1000;
        long testValue = 1;

        //.NET 4.0. Release build. Mean time - 26 secs;
        object lockObject = new object();
        Stopwatch sw = Stopwatch.StartNew();
        for (int i = 0; i < iterations; i++)
        {
            lock (lockObject)
            {
                testValue++;    
            }
        }
        sw.Stop();

        //Java 6.25. Default JVM params. Mean time - 17 secs.
        Object lock = new Object();
        long start = System.currentTimeMillis();
        for (int i = 0; i < iterations; i++)
        {
                synchronized (lock)
                {
                    testValue++;
                }
        }
        long stop = System.currentTimeMillis();

似乎在.NET中使用 signle 线程获取场景中的锁的成本仅比在 Java 中高出 50%。起初我对计时器持怀疑态度,但我已经运行了几次相同的测试,结果与上述平均值差不多。然后我对同步代码块持怀疑态度,但它所做的不仅仅是monitorenter / monitorexit字节代码指令 - 与.NET中的lock关键字相同。任何其他想法为什么在.NET与Java中采用锁如此昂贵?


答案 1

是的,看起来在.NET中使用未控制的锁比在Java中更昂贵。(我的上网本上的结果仍然稍微引人注目。

性能的各个方面在一个平台上会比另一个平台更快,有时甚至达到这个程度。HotSpot JIT和.NET JIT在各个方面都非常不同 - 尤其是因为.NET JIT只在IL上运行一次,而HotSpot能够随着特定代码越来越频繁地运行而进行越来越多的优化。

重要的问题是这是否真的重要。如果你的实际应用程序花费真的每分钟获得5亿次无争议的锁,那么它可能很重要 - 你应该重新设计你的应用程序。如果您的实际应用程序实际上在锁内(或在锁的购买之间)实际工作,那么它不太可能成为真正的瓶颈。

我最近发现了两个.NET陷阱(第一部分;第二部分)当我编写“系统级库”时,我不得不四处工作,当应用程序执行大量日期/时间解析时,它们会产生显着差异 - 但这种微优化很少值得做。


答案 2

关于微基准测试,首先要记住的是,Java特别擅长识别和消除不做任何事情的代码。我一次又一次地发现,Java比任何其他语言更快地完成毫无意义的代码。;)

如果与另一种语言相比,Java的速度惊人,那么第一个问题应该是;代码是否执行任何远程有用的操作?(甚至看起来它可能有用)

Java倾向于比以前更多地循环展开。它还可以组合锁。由于您的测试是无可争议的,并且确实可以执行任何操作,因此您的代码看起来像这样。

for (int i = 0; i < iterations; i+=8) {
    synchronized (lock) {
        testValue++;
    }
    synchronized (lock) {
        testValue++;
    }
    synchronized (lock) {
        testValue++;
    }
    synchronized (lock) {
        testValue++;
    }
    synchronized (lock) {
        testValue++;
    }
    synchronized (lock) {
        testValue++;
    }
    synchronized (lock) {
        testValue++;
    }
    synchronized (lock) {
        testValue++;
    }
}

这成为

for (int i = 0; i < iterations; i+=8) {
    synchronized (lock) {
        testValue++;
        testValue++;
        testValue++;
        testValue++;
        testValue++;
        testValue++;
        testValue++;
        testValue++;
    }
}

因为不使用 testValue。

for (int i = 0; i < iterations; i+=8) {
    synchronized (lock) {
    }
}

最后

{ }

推荐