繁体   English   中英

Java CAS操作的执行速度比C等效的快,为什么?

[英]Java CAS operation performs faster than C equivalent, why?

  • 这里我有Java和C代码尝试使用CAS进行原子增量操作。
  • 将长变量从0增加到500,000,000。
  • C:所用时间:7300ms
  • Java:拍摄时间:2083ms
  • 任何人都可以仔细检查这些结果吗? 因为我简直无法相信他们。
  • 谢谢

Java代码:

import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;

public class SmallerCASTest {

    public static void main(String[] args){
        final long MAX = 500l * 1000l * 1000l;
        final AtomicLong counter = new AtomicLong(0);

        long start = System.nanoTime();
        while (true) {
            if (counter.incrementAndGet() >= MAX) {
                break;
            }
        }

        long casTime = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - start);
        System.out.println("Time Taken=" + casTime + "ms");
    }

}

C代码:

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define NITER 500000000


int main (){
   long val = 0;     
   clock_t starttime = clock ();
    while (val < NITER){
      while (1){
        long current = val;
        long next = current+1;
        if ( __sync_bool_compare_and_swap (&val, current, next))
            break;
      }
     } 
   clock_t castime = (clock()-starttime)/ (CLOCKS_PER_SEC / 1000);
   printf ("Time taken : %d ",castime);
}

run.sh

#!/bin/bash

gcc -O3 test.c -o test.o
echo -e "\nC"
./test.o
javac SmallerCASTest.java
echo -e "\nJava"
java SmallerCASTest

其他详情:

System : Linux XXXXXXXXX #1 SMP Thu Mar 22 08:00:08 UTC 2012 x86_64 x86_64 x86_64 GNU/Linux

gcc --version:
 gcc (GCC) 4.4.6 20110731 (Red Hat 4.4.6-3)

java -version: 
java version "1.6.0_31"
Java(TM) SE Runtime Environment (build 1.6.0_31-b04)
Java HotSpot(TM) 64-Bit Server VM (build 20.6-b01, mixed mode)

你正在比较苹果和橘子,我相信你的预期。 java版本是一个真正的CAS,在失败时重试,而C版本使用我在java调用的synchronized形式。

有关详细信息,请参阅此问题

请参阅该问题的答案以获得支持叙述,其中表示A full memory barrier is created when this function is invoked ,即在java术语中,这是一个synchronized调用。

尝试使用_compare_and_swap ,就像AtomicLong使用它的java等价物一样,即旋转函数,直到值改变为你想要的值。

添加:

我找不到与Java AtomicLong相当的确定C ++,但这并不意味着没有一个。 从本质上讲, AtomicLong可以随时由任何线程更改,只有其中一个成功。 但是,更改将是一致的,即更改将是由一个或另一个线程更改的结果,它不会是两者的组合。 如果线程A尝试将值更改为0xffff0000(或等效的64位数),而线程B尝试更改为0x0000ffff(同上),则结果将是两个值中的任何一个,更具体地说,它将不是 0x00000000或0xffffffff(除非是当然第三个线程涉及)。

从本质上讲, AtomicLongAtomicLong 没有任何同步

编辑事实上,正如你所指出的,java似乎使用CAS操作实现incrementAndGet。

我的测试似乎表明C和Java版本具有大致相同的性能(这是有道理的,因为耗时的部分是原子而不是java或C编译器设法做的其余部分的优化)。

所以在我的机器(Xeon X3450)上,java版本需要大约4700毫秒,C版本大约4600毫秒,一个C版本使用__sync_add_and_fetch()~3800毫秒(这表明可以在这里改进java而不是实现所有的原子操作CAS的顶部)。

java版本是


java version "1.6.0_24"
OpenJDK Runtime Environment (IcedTea6 1.11.4) (6b24-1.11.4-1ubuntu0.10.04.1)
OpenJDK 64-Bit Server VM (build 20.0-b12, mixed mode)

GCC是4.4.3,x86_64。

操作系统是Ubuntu 10.04 x86_64。

所以我只能得出结论,在你的测试中看起来有点可疑。

因为Java很棒?

每个循环java版本需要4ns。 那是对的。 无竞争CAS实际上是CPU本地操作,它应该非常快。 (编辑:可能不是4ns快!)

Java通过积极的运行时优化实现了这种速度,代码被内联并成为几个机器指令,即尽可能快地在汇编中手动编写代码。

如果gcc版本无法内联函数调用,那么每个循环的开销很大。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM