为了全部代码结果可重现,下面会列出各语言的版本。我的 ruby 版本是
$ ruby -v
ruby 2.1.0dev (2013-04-17) [x86_64-darwin12.3.0]
下面两段代码都创建了两个字符串对象,两个长度都差不多 100M
mem.rb
s = '-' * 100_000_000
b = s[1..-1]
puts b.size
gets
mem.cpp
#include <string>
#include <cstdlib>
#include <cstdio>
using namespace std;
int main (int argc, char const *argv[]) {
string s = string(100000000, '-');
string b = string(s, 1);
printf("%lu\n", b.size());
getchar();
return 0;
}
我比较土,加个 getc
然后在 activity monitor 看内存...
$ clang++ -v
Apple LLVM version 4.2 (clang-425.0.24) (based on LLVM 3.2svn)
Target: x86_64-apple-darwin12.3.0
Thread model: posix
$ clang++ mem.cpp
$ ./a.out # c++ 使用内存 191.3M
$ ruby mem.rb # ruby 使用内存 101.7M
原因: ruby 字符串实现是 copy-on-write 的,c++ 在 constructor 处就要拷贝一遍了。
之前的一个回复里和 javascript 比较过模板渲染速度了,ruby 每秒 70000+ 完胜... 和静态语言比的话,最好欺负的就是 go 了,下面是 go 渲染同样的模板的代码:
a.gt
<div>
<h1 class='header'>{{.Header}}</h1>
<h2 class='header2'>{{.Header2}}</h2>
<h3 class='header3'>{{.Header3}}</h3>
<h4 class='header4'>{{.Header4}}</h4>
<h5 class='header5'>{{.Header5}}</h5>
<h6 class='header6'>{{.Header6}}</h6>
<ul class='list'>
{{range .List}}
<li class='item'>{{.}}</li>
{{end}}
</ul>
</div>
b.go
package main
import (
"text/template"
"io/ioutil"
"bytes"
"fmt"
"time"
)
type Context struct {
Header string
Header2 string
Header3 string
Header4 string
Header5 string
Header6 string
List []string
}
func main() {
b, err := ioutil.ReadFile("a.gt")
if err != nil {
panic("template a.gt not found!")
}
t, _ := template.New("foo").Parse(string(b))
context := Context{
"Header",
"Header2",
"Header3",
"Header4",
"Header5",
"Header6",
[]string{"1000000000", "2", "3", "4", "5", "6", "7", "8", "9", "10"},
}
var out bytes.Buffer
t.Execute(&out, context)
fmt.Println(out.String())
start := time.Now()
for n := 0; n < 100000; n++ {
t.Execute(&out, context)
}
fmt.Println(time.Now().Sub(start))
}
执行
$ go version
go version go1.0.3
$ go run b.go
...
4.084225s
故 go template 的渲染速度是 100000/4.08 = 2.4 万/s, 约为 ruby 的 1/3.
原因: slim 是编译器,效果相当于用 ruby 的字节码解释器执行模板。go 由于是静态语言,没有 eval
这种邪恶的方法,所以 go template 只能用很原始的树遍历解释器来实现模板语言,还是要比字节码解释器慢很多的。
继 ruby 在 hello world 的性能和内存占用完胜 java 以后,又迎来新的突破...
下面的例子很久之前发过一遍,但因为回档没了... 再发一遍吧
下面两段代码都是用同一段口令,同一种加密方式 (aes-256-cbc, ssh 库或者口令加密一些小文件会经常用到的), 加密同一段明文 1000 次。另外 ruby 脚本还做了点额外的事情:把明文和键保存到文件中方便对应的 java 程序读入。java 代码中调整了方法的位置,并换用 server compiler 以保证有最高的效率。
aes.rb
require "openssl"
$str = File.read(__FILE__) * 1000
$key = 'm23a0sdf' * 4
# store them for java testing
File.open 'ptext', 'w' do |f|
f << $str
end
File.open 'key', 'w' do |f|
f << $key
end
def crypt
1000.times do
c = OpenSSL::Cipher.new 'aes-256-cbc'
c.encrypt
c.key = $key
c.update $str
c.final
end
end
t = Time.now.to_f
crypt
diff = (Time.now.to_f - t) * 1000
puts "finished in #{diff} ms"
aes.java
import java.security.*;
import javax.crypto.*;
import javax.crypto.spec.*;
import java.io.*;
class aes{
static byte[] ptext;
static SecretKeySpec key;
public static void main(String[] args) throws Exception {
ptext = read("ptext");
key = new SecretKeySpec(read("key"), "AES");
long t = System.currentTimeMillis();
doCiphers();
System.out.println("finished in " + (System.currentTimeMillis() - t) + " ms");
}
// wrap the loop inside a method to enable JIT
static void doCiphers() throws Exception {
for (int i=0; i<1000; i++) {
Cipher c = Cipher.getInstance("AES");
c.init(Cipher.ENCRYPT_MODE, key);
c.doFinal(ptext);
}
}
static byte[] read(String fileName) throws Exception {
RandomAccessFile f = new RandomAccessFile(fileName, "r");
byte[] b = new byte[(int)f.length()];
f.read(b);
f.close();
return b;
}
}
执行
$ ruby aes.rb
finished in 1003.9401054382324 ms
$ java -version
java version "1.6.0_45"
Java(TM) SE Runtime Environment (build 1.6.0_45-b06-451-11M4406)
Java HotSpot(TM) 64-Bit Server VM (build 20.45-b01-451, mixed mode)
$ javac aes.java
$ java -d64 -server aes
finished in 4720 ms
原因: ruby 链接到了 openssl 1.0.1e, 而 openssl 的实现是直接使用了 i7 处理器的 aes 指令。而 java 的 jce 标准库是用了 bountycastle 纯 java 的实现。你可以说它实际上比较的是 asm 和 java...
另外有 jdk7 和 jdk8 也可以试试,结果差别应该不大。另外如果处理器不支持 aes 指令,差距就会小很多。
mac osx 看处理器是否支持 aes:
$ sysctl -a | grep aes
746:hw.optional.aes: 1
mac osx 看 ruby 链接到哪个 openssl (各人系统或者 ruby 版本不同的话路径会略有区别):
$ otool -L ~/.rvm/rubies/ruby-head/lib/ruby/2.1.0/x86_64-darwin12.3.0/openssl.bundle
/Users/z/.rvm/rubies/ruby-head/lib/ruby/2.1.0/x86_64-darwin12.3.0/openssl.bundle:
/usr/local/opt/openssl/lib/libssl.1.0.0.dylib (compatibility version 1.0.0, current version 1.0.0)
/usr/local/opt/openssl/lib/libcrypto.1.0.0.dylib (compatibility version 1.0.0, current version 1.0.0)
...
待编辑... 想整个爬虫的例子。另外还想整个把 ruby 代码自动翻译 OpenCL 的 GPGPU-JIT 例子,不过坑略大...