在.NET与Java中锁定的成本

And*_*nov 28 c# java performance locking synchronized

我正在使用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();
Run Code Online (Sandbox Code Playgroud)

似乎在.NET中使用signle线程获取锁定的成本仅比Java高50%.起初我对计时器很怀疑,但我已经进行了几次相同的测试,结果只是提到了上面的平均值.然后我对同步代码块感到怀疑,但它只不过是monitorenter/monitorexit字节代码指令 - 与.NET中的lock关键字相同.在.NET与Java中,为什么采取锁定的任何其他想法都是如此昂贵?

Jon*_*eet 22

是的,看起来在.NET中使用无竞争锁定比在Java中更昂贵.(我的上网本上的结果仍然略显引人注目.)

性能的各个方面在一个平台上比另一个平台更快,有时在这个程度上.HotSpot JIT和.NET JIT在各方面都完全不同 - 尤其是因为.NET JIT只在IL上运行一次,而HotSpot能够越来越多地优化,因为特定的代码片段运行得越来越频繁.

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

我最近发现了两个.NET陷阱(第一部分 ;第二部分),当我正在编写一个"系统级库"时,我需要解决它们,当应用程序执行大量日期时它们会产生重大影响/时间解析 - 但这种微优化很少值得做.


Pet*_*rey 8

关于微基准测试,首先要记住的是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++;
    }
}
Run Code Online (Sandbox Code Playgroud)

变成了

for (int i = 0; i < iterations; i+=8) {
    synchronized (lock) {
        testValue++;
        testValue++;
        testValue++;
        testValue++;
        testValue++;
        testValue++;
        testValue++;
        testValue++;
    }
}
Run Code Online (Sandbox Code Playgroud)

因为没有使用testValue.

for (int i = 0; i < iterations; i+=8) {
    synchronized (lock) {
    }
}
Run Code Online (Sandbox Code Playgroud)

最后

{ }
Run Code Online (Sandbox Code Playgroud)

  • @RoundTower ...需要时间来确定循环是否值得展开,确定锁是否可以合并,以及执行转义分析.有时候循环可能已经部分计算出来了......在任何情况下,"JVM真的很糟糕"既不是一个有用的也不是知情的陈述. (3认同)