是这样的:
cat sum100000000.cpp && cat sum100000000.java
#include <cstdio>
using namespace std;
int main(){
long N=1000000000,sum=0;
for( long i=0; i<N; i++ ) sum+= i;
printf("%ld\n",sum);
}
public class sum100000000 {
public static void main(String[] args) {
long sum=0;
for(long i = 0; i < 1000000000; i++) sum += i;
System.out.println(sum);
}
}
这是结果:
time ./a.out && time java sum100000000
499999999500000000
real 0m2.675s
user 0m2.673s
sys 0m0.002s
Picked up JAVA_TOOL_OPTIONS: -Dfile.encoding=UTF-8
499999999500000000
real 0m0.439s
user 0m0.470s
sys 0m0.027s
在反汇编的二进制文件中没有发现任何异常。但似乎 c 二进制文件要慢得多。我无法理解。
我的猜测是工具链可能有问题
clang -v
Apple LLVM version 5.1 (clang-503.0.40) (based on LLVM 3.4svn)
Target: x86_64-apple-darwin13.4.0
Thread model: posix
uname -a
Darwin MacBook-Pro.local 13.4.0 Darwin Kernel Version 13.4.0: Sun Aug 17 19:50:11 PDT 2014; root:xnu-2422.115.4~1/RELEASE_X86_64 x86_64
添加:c/cpp编译时没有任何特殊的二进制文件。无论如何,这不会改变结果。
gcc sum1b.cpp
clang sum1b.cpp
补充:对于那些关心 llvm 的人,真的没有改变任何东西
$ gcc sum100000000.cpp && time ./a.out
gcc sum100000000.cpp && time ./a.out
499999999500000000
real 0m2.722s
user 0m2.717s
sys 0m0.003s
修改:O2 快了很多:但这看起来像是作弊
$ otool -tV a.out
otool -tV a.out
a.out:
(__TEXT,__text) section
_main:
0000000100000f50 pushq %rbp
0000000100000f51 movq %rsp, %rbp
0000000100000f54 leaq 0x37(%rip), %rdi ## literal pool for: "%ld
"
0000000100000f5b movabsq $0x6f05b59b5e49b00, %rsi
0000000100000f65 xorl %eax, %eax
0000000100000f67 callq 0x100000f70 ## symbol stub for: _printf
0000000100000f6c xorl %eax, %eax
0000000100000f6e popq %rbp
0000000100000f6f ret
我现在确信这与优化有关,所以现在更多的问题是 JIT 到底做了什么来加速这个计算?
最佳答案
问题很可能是您没有在启用优化的情况下编译 C 版本。如果启用积极优化,则 gcc 生成的二进制文件应该会获胜。 JVM 的 JIT 很好,但简单的事实是 JVM 必须在运行时加载然后应用 JIT; gcc 可以在编译时优化二进制文件。
离开所有 gcc 标志给我一个执行相当慢的二进制文件,就像你的一样。使用 -O2 给我一个二进制文件,几乎不输给 Java 版本。使用 -O3 可以轻松击败 Java 版本。 (这是在我的 Linux Mint 16 64 位机器上使用 gcc 4.8.1 和 Java 1.8.0_20 [例如,Java 8 Update 20]。)larsmans检查了 -O3 版本的反汇编,并向我保证编译器没有预先计算结果(这些天我的 C 和汇编 fu 非常很弱;非常感谢 larsmans仔细检查)。不过,有趣的是,感谢 Mat 的调查,看起来这实际上是我使用 gcc 4.8.1 的副产品; gcc 的早期和更新版本似乎愿意预先计算结果。不过,对我们来说是个幸运的意外。
这是我的纯 C 版本 [我还更新了它以说明 Ajay's comment关于您在 Java 版本中使用常量,但在 C 版本中使用变量 N(没有任何真正的区别,但是......)]:
sum.c:
#include <stdio.h>
int main(){
long sum=0;
long i;
for( i=0; i<1000000000; i++ ) sum+= i;
printf("%ld\n",sum);
}
除了我太容易忘记零之外,我的 Java 版本与您的没有变化:
sum.java:
public class sum {
public static void main(String[] args) {
long sum=0;
for(long i = 0; i < 1000000000; i++) sum += i;
System.out.println(sum);
}
}
结果:
C 二进制运行(通过 gcc sum.c 编译):
$ time ./a.out 499999999500000000 real 0m2.436s user 0m2.429s sys 0m0.004s
Java 运行(没有特殊标志编译,没有特殊运行时标志运行):
$ time java sum 499999999500000000 real 0m0.691s user 0m0.684s sys 0m0.020s
Java 运行(编译时没有特殊标志,使用 -server -noverify 运行,微小改进):
$ time java -server -noverify sum 499999999500000000 real 0m0.651s user 0m0.649s sys 0m0.016s
C 二进制运行(通过 gcc -O2 sum.c 编译):
$ time ./a.out 499999999500000000 real 0m0.733s user 0m0.732s sys 0m0.000s
C 二进制运行(通过 gcc -O3 sum.c 编译):
$ time ./a.out 499999999500000000 real 0m0.373s user 0m0.372s sys 0m0.000s
这是在我的 -O3 版本上 objdump -d a.out 的 main 结果:
0000000000400470 : 400470: 66 0f 6f 1d 08 02 00 movdqa 0x208(%rip),%xmm3 # 400680 400477: 00 400478: 31 c0 xor %eax,%eax 40047a: 66 0f ef c9 pxor %xmm1,%xmm1 40047e: 66 0f 6f 05 ea 01 00 movdqa 0x1ea(%rip),%xmm0 # 400670 400485: 00 400486: eb 0c jmp 400494 400488: 0f 1f 84 00 00 00 00 nopl 0x0(%rax,%rax,1) 40048f: 00 400490: 66 0f 6f c2 movdqa %xmm2,%xmm0 400494: 66 0f 6f d0 movdqa %xmm0,%xmm2 400498: 83 c0 01 add $0x1,%eax 40049b: 66 0f d4 c8 paddq %xmm0,%xmm1 40049f: 3d 00 65 cd 1d cmp $0x1dcd6500,%eax 4004a4: 66 0f d4 d3 paddq %xmm3,%xmm2 4004a8: 75 e6 jne 400490 4004aa: 66 0f 6f e1 movdqa %xmm1,%xmm4 4004ae: be 64 06 40 00 mov $0x400664,%esi 4004b3: bf 01 00 00 00 mov $0x1,%edi 4004b8: 31 c0 xor %eax,%eax 4004ba: 66 0f 73 dc 08 psrldq $0x8,%xmm4 4004bf: 66 0f d4 cc paddq %xmm4,%xmm1 4004c3: 66 0f 7f 4c 24 e8 movdqa %xmm1,-0x18(%rsp) 4004c9: 48 8b 54 24 e8 mov -0x18(%rsp),%rdx 4004ce: e9 8d ff ff ff jmpq 400460
正如我所说,我的汇编功能很弱,但我在那里看到了一个循环,而不是编译器完成了数学计算。
为了完整起见,javap -c sum 结果的 main 部分:
public static void main(java.lang.String[]);
Code:
0: lconst_0
1: lstore_1
2: lconst_0
3: lstore_3
4: lload_3
5: ldc2_w #2 // long 1000000000l
8: lcmp
9: ifge 23
12: lload_1
13: lload_3
14: ladd
15: lstore_1
16: lload_3
17: lconst_1
18: ladd
19: lstore_3
20: goto 4
23: getstatic #4 // Field java/lang/System.out:Ljava/io/PrintStream;
26: lload_1
27: invokevirtual #5 // Method java/io/PrintStream.println:(J)V
30: return
它不是在字节码级别预先计算结果;我不能说 JIT 在做什么。
关于java - 对十亿整数求和时,c 比 java 慢,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26815471/
我真的很习惯使用Ruby编写以下代码:my_hash={}my_hash['test']=1Java中对应的数据结构是什么? 最佳答案 HashMapmap=newHashMap();map.put("test",1);我假设? 关于java-等价于Java中的RubyHash,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/22737685/
我正在尝试使用boilerpipe来自JRuby。我看过guide从JRuby调用Java,并成功地将它与另一个Java包一起使用,但无法弄清楚为什么同样的东西不能用于boilerpipe。我正在尝试基本上从JRuby中执行与此Java等效的操作:URLurl=newURL("http://www.example.com/some-location/index.html");Stringtext=ArticleExtractor.INSTANCE.getText(url);在JRuby中试过这个:require'java'url=java.net.URL.new("http://www
我只想对我一直在思考的这个问题有其他意见,例如我有classuser_controller和classuserclassUserattr_accessor:name,:usernameendclassUserController//dosomethingaboutanythingaboutusersend问题是我的User类中是否应该有逻辑user=User.newuser.do_something(user1)oritshouldbeuser_controller=UserController.newuser_controller.do_something(user1,user2)我
什么是ruby的rack或python的Java的wsgi?还有一个路由库。 最佳答案 来自Python标准PEP333:Bycontrast,althoughJavahasjustasmanywebapplicationframeworksavailable,Java's"servlet"APImakesitpossibleforapplicationswrittenwithanyJavawebapplicationframeworktoruninanywebserverthatsupportstheservletAPI.ht
这篇文章是继上一篇文章“Observability:从零开始创建Java微服务并监控它(一)”的续篇。在上一篇文章中,我们讲述了如何创建一个Javaweb应用,并使用Filebeat来收集应用所生成的日志。在今天的文章中,我来详述如何收集应用的指标,使用APM来监控应用并监督web服务的在线情况。源码可以在地址 https://github.com/liu-xiao-guo/java_observability 进行下载。摄入指标指标被视为可以随时更改的时间点值。当前请求的数量可以改变任何毫秒。你可能有1000个请求的峰值,然后一切都回到一个请求。这也意味着这些指标可能不准确,你还想提取最小/
HashMap中为什么引入红黑树,而不是AVL树呢1.概述开始学习这个知识点之前我们需要知道,在JDK1.8以及之前,针对HashMap有什么不同。JDK1.7的时候,HashMap的底层实现是数组+链表JDK1.8的时候,HashMap的底层实现是数组+链表+红黑树我们要思考一个问题,为什么要从链表转为红黑树呢。首先先让我们了解下链表有什么不好???2.链表上述的截图其实就是链表的结构,我们来看下链表的增删改查的时间复杂度增:因为链表不是线性结构,所以每次添加的时候,只需要移动一个节点,所以可以理解为复杂度是N(1)删:算法时间复杂度跟增保持一致查:既然是非线性结构,所以查询某一个节点的时候
遍历文件夹我们通常是使用递归进行操作,这种方式比较简单,也比较容易理解。本文为大家介绍另一种不使用递归的方式,由于没有使用递归,只用到了循环和集合,所以效率更高一些!一、使用递归遍历文件夹整体思路1、使用File封装初始目录,2、打印这个目录3、获取这个目录下所有的子文件和子目录的数组。4、遍历这个数组,取出每个File对象4-1、如果File是否是一个文件,打印4-2、否则就是一个目录,递归调用代码实现publicclassSearchFile{publicstaticvoidmain(String[]args){//初始目录Filedir=newFile("d:/Dev");Datebeg
我基本上来自Java背景并且努力理解Ruby中的模运算。(5%3)(-5%3)(5%-3)(-5%-3)Java中的上述操作产生,2个-22个-2但在Ruby中,相同的表达式会产生21个-1-2.Ruby在逻辑上有多擅长这个?模块操作在Ruby中是如何实现的?如果将同一个操作定义为一个web服务,两个服务如何匹配逻辑。 最佳答案 在Java中,模运算的结果与被除数的符号相同。在Ruby中,它与除数的符号相同。remainder()在Ruby中与被除数的符号相同。您可能还想引用modulooperation.
Java的Collections.unmodifiableList和Collections.unmodifiableMap在Ruby标准API中是否有等价物? 最佳答案 使用freeze应用程序接口(interface):Preventsfurthermodificationstoobj.ARuntimeErrorwillberaisedifmodificationisattempted.Thereisnowaytounfreezeafrozenobject.SeealsoObject#frozen?.Thismethodretur
有没有一种简单的方法可以将给定的整数格式化为具有固定长度和前导零的字符串?#convertnumberstostringsoffixedlength3[1,12,123,1234].map{|e|???}=>["001","012","123","234"]我找到了解决方案,但也许还有更聪明的方法。format('%03d',e)[-3..-1] 最佳答案 如何使用%1000而不是进行字符串操作来获取最后三位数字?[1,12,123,1234].map{|e|format('%03d',e%1000)}更新:根据theTinMan的