Ruby [扬长避短] cruby 在什么情况下比 C++, JavaScript, Go, Java, Haskell 更效率...

luikore · 2013年04月19日 · 最后由 chenge 回复于 2016年07月04日 · 17865 次阅读
本帖已被管理员设置为精华贴

为了全部代码结果可重现, 下面会列出各语言的版本. 我的 ruby 版本是

$ ruby -v
ruby 2.1.0dev (2013-04-17) [x86_64-darwin12.3.0]

ruby 在什么情况比 c++ 省内存

下面两段代码都创建了两个字符串对象, 两个长度都差不多 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 处就要拷贝一遍了.


ruby 在什么情况比 go 快

之前的一个回复里和 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 在什么情况下调库函数比 java 效率

继 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 在什么情况比 haskell 更并行

待编辑... 想整个爬虫的例子. 另外还想整个把 ruby 代码自动翻译 OpenCL 的 GPGPU-JIT 例子, 不过坑略大...

拜读营养帖

一直对 “XXX 比 Ruby 快 X 倍” 的宣言没啥兴趣,对我来说 Ruby 足够好,而且熟悉,适合用于快速开发。

由于缺乏底层知识一直不能从技术上反对 “快 X 倍” 的宣言,楼主让我学习了。

扬长避短 才是这个帖子要说明的真谛:)

默默的点了 like 跟收藏。。。

libc++ 的确不是 COW 的,但谁告诉你 C++ std::string 不能是 COW 的? 还拿什么 hello world 的性能和内存比,有意思么?有些情况下 js 都比 c 快呢

#6 楼 @kkk 可以啊, 不过我避而不谈... 求 js 比 c 快的例子.

hello world 性能对于完成日常小任务的脚本很重要的. 你用 java 实现个 brew 看看, 看它不卡死你.

#7 楼 @luikore https://github.com/felixge/faster-than-c 另你可以 google "xxx faster than yyy" 不管 xxx,yyy 是何种(流行的)语言,总能找到很多例子

#9 楼 @kkk

那个是噱头啊, 看 readme:

This talk is analyzing the performance of JavaScript vs C-Bindings for MySQL in node.js, but not JavaScript vs. C itself.

很多语言的优化 (如分代 GC 要移动对象) 会搞得 FFI 很复杂, 所以 C-binding 速度很慢. Ruby 就是完全不做这类优化, 所以 C-binding 速度很快...

这帖子太深了

#10 楼 @luikore 哈哈,你这帖子也是噱头阿,很多不过是底层类库的实现区别而已,到了不同平台不同版本实现不一样了很可能就是完全不同的结果。你认为是 “扬长避短”,我认为是 “田忌赛马” 😏

#12 楼 @kkk 是的, 社会上都在说 ruby 死慢... 所以我才整几个 controversal 的例子...

别处没感觉到 ruby 慢,rails console 和 rspec 启动慢很是郁闷,每次要盯着屏幕发呆一段时间才能看到运行结果。光是解决这个慢的问题,又出了 n 种 gem 解决方案,然后每个方案里面又可能有 n 个坑

语言达人啊,这个得对底层非常了解,吾等只会写业务代码,真是只能看看了。

👍 做成个 conference talk 如何?

#14 楼 @gaicitadie 没对比 所以没感觉。

#14 楼 @gaicitadie 一直用 Zeus,从未被超越。

黑 go 的那段太没水平, go run 是包含编译过程的, 要比就得

go build b.go time ./b

#19 楼 @wendal


故 go template 的渲染速度是 100000/4.08 = 2.4 万/s, 约为 ruby 的 1/3.

原因: slim 是编译器, 效果相当于用 ruby 的字节码解释器执行模板. go 由于是静态语言, 没有 eval 这种邪恶的方法, 所以 go template 只能用很原始的树遍历解释器来实现模板语言, 还是要比字节码解释器慢很多的.


在我的机器上, 执行耗时仅 59ms 相当于每秒 169w 次, 你觉得是 ruby 的多少倍呢? 秒杀 ruby 几百条街

掉包了!。。

各位要把这些个例子都跑跑试试哇……

要求 速度比C++快,并行度比go高,库函数比haskell效率,bytecode比Java向前兼容时间长

楼主 这个帖子也是在说明网络上一些所谓的 benchmark 是没什么具体意义的。 尤其是用不同的语言,却使用雷同的写法,这样就更不准确了(网上这类的 benchmark 太多了)。因为每个语言的特性都不一样,应该是按各自语言合理高效的写法,而不是用雷同的写法。

比如: Ruby 代码:


def orz(s)
  .......
end
10000000.times{ orz(s) }

C++ 代码:

void orz(string s){
  ......
}
for(size_t i; i < 10000000; ++i){ orz(s) }

看似两个代码类似,实际上,这对 C++ 来说是并不高效的,因为 orz(string s)是按值传递参数,这样每次调用orz都会多生产一份儿 s 的拷贝副本,在循环次数多,字符串较长的时候,副作用会更明显。 如果改为引用的形式 orz(string & s)orz(const string & s), 这样 s 就是按引用传递,不会产生多余的副本,性能也能提高。

还有一个例子: C++ 中的new和 Java 中的new 是不一样的(虽然摸样一样 @_@)。以前看过一个 benchmark,他是将 java 代码基本原样翻成了 C++代码。完全违背了 C++的高效写法。所以,benchmark 的结果可想而知。

我想说的是:不同的语言,雷同的写法也会带来误导的结果

最近,在批改新员工作业时,有一个 C 语言 作业运行约 15 秒,我修改掉其中的 2 行代码,结果运行时间只花了 0.3 秒,差距巨大。如果对语言掌握的不扎实,很有可能会写出很慢很慢的程序。

to @luikore @bhuztez @wendal 我觉得这篇帖子的意义非常好: 要扎实的掌握你所掌握语言,才能 “扬长避短”,最大发挥语言的效能。如果再能掌握一些底层知识和 VM 的相关知识,就能更好的避开一些语言的陷阱了。也会更明白一些所谓的 benchmark 只是...... 呵呵。

#20 楼 @wendal 你的机器真好, 我的机器上 go build 以后和 go run 结果是一样的, 你用的 go 版本是什么? 不会是 gccgo 吧? 你跑这段渲染有结果么?

#23 楼 @bhuztez ... 例子一改改是可以比 C++ 快的, 其它的就靠你了

@wendal 我为了让例子中的 go 代码尽可能跑得快, 还专门用了 text/template 而不是 html/template, 你 time 出来的 59ms 忽略了 system 部分吧

老实说 go 这个慢都能感觉出来的...

#24 楼 @skandhas C++ string 各种坑... 每个库干事情之前都先自己定义一个新的 string 类...

#28 楼 @luikore 嗯 确实如此。 std::string 的坑大是出了名的啦。@_@

H:\wirelessw\box\src\github.com\wendal\simples>go run main.go

72.5093ms

软件配置: golang 1.1beta2 win7 sp1 x64 硬件: i5-2410M 8G 内存

楼上用 windows v5

我本机 go 测试的是

go build b.go
./b
5.090454s

#6 楼 @kkk #7 楼 @luikore 6 楼这个 kkk ID 很新哦,特地上来喷的?

这不叫扬长,只是取巧罢了,其他语言都可以的。

第一个例子,如果就取一个.size, c++ 可以做到 90 多 M。 关于 go 的不是很清楚,不好说话。 关于 java 的例子,你是其实是拿 c 库和 java 实现比,根 ruby 关系不大。

ruby 比性能和内存,从哪一方面来说都没有优势,没有可谈的什么过人之处,从实现角度来看,他现在瓶颈了,你认为 1.87 到 2.0 有什么改进? yacc 有进步吗,都没人接手了吧。 jit 有实现? 这些,你看看 python,js,java 人家都很强哦。 所以我觉得他应该会慢到底,不可能像 java 一样能有那么大的改进。

再一个慢不慢,大家自己实际用了心理很清楚,yy 时间和数据没多大意思。 试试 rails s django server node app.js

至于应用实现快不快,完全取决于你的熟练度,语言本身性能占的比重可能没那么多。

#33 楼 @ShiningRay

你说@kkk来喷的证据就是他的 id 新吗?就事论事,反驳他的观点就好了。

#34 楼 @hhuai c++ 换个难看的写法是可以. java 的例子已经比曼德布罗集或者 n 体问题 之类的八辈子都用不到的 benchmark 有实用意义多了.

ruby 做命令行工具的性能和内存优势都很大.

ruby 也有带 jit 的实现: rubinius. 算上 jruby 的话就是有两个带 jit 的实现了. 官方 python 也和 cruby 一样没有 jit 的哦. jit 说白了就是用内存和代码的灵活度换性能. 例如在 js 的代码里轮流给一个变量赋不同的类型的值, jit 的 assumption 就会被打破, 会拖慢程序... 另外不区分整型和浮点的 js 本身就是残废语言, 和主题无关就不展开了...

#36 楼 @luikore rubinius 无实用价值, jruby 还是 java. 在我看看恰恰你所说的残废语言,现在发展势头最猛,好几大公司都在改进

ruby 做命令行工具的性能和内存优势都很大,这个我同意,还不错,只是要说在性能和内存把其他语言比,这个本身有点 yy.

#30 楼 @wendal 好吧刚 checkout 了 go 的 edge 版本, 在我的机器上速度有较大改进, 接近 ruby slim 了.

$ go version
go version devel +13e00572ed0b Thu Apr 18 17:37:21 2013 -0700 darwin/amd64
$ go build b.go
$ time ./b
...
1.415287306s
./b  1.38s user 0.05s system 100% cpu 1.435 total

还是比 ruby 慢一点, 如果换成 html/template:

$ time ./b
6.516209338s
./b  6.45s user 0.11s system 100% cpu 6.554 total

#37 楼 @hhuai 你可以试试跑跑这几个例子, 我都把原因列出来了, 什么地方解释得不对的请指正. 你可以说大部分情况下 ruby 慢成一坨屎, 但这几个例子都是事实不是 yy. (除了 go 的例子和 @wendal 大大执行的结果不一样...)

win7 64bit sp1, athlon x2 250, 4G,go 1.1beta2,平均 75ms 左右 linux 3.2 64bit 的虚拟机,go 1.0.2,平均 100ms 左右 应该是 go 在 mac 上的实现有问题

#39 楼 @luikore 第一个,我可以这么写

~$ more /tmp/test.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct string{
        int length;
        char p[1];
} string;

#define MALLOC_SIZE 100000000
int main(){
        char *s = (char *)malloc(MALLOC_SIZE);
        memset(s,'-',MALLOC_SIZE);
        string ss ={MALLOC_SIZE, s};
        string b = {ss.length-1, ss.p+1};

        printf("%ld",b.length);
        getchar();

        return 0;
}

#39 楼 @luikore 我怀疑是不是他没在 b.go 文件同路径下创建 a.gt 这个模板文件造成的。。。

大家无视我 golang 的测试结果, 是我错了 --> 撞墙中

@reus @wendal 我正在往 linux 机装 go 中... 可能真是 mac 的错...

噗,我也错了 …………

#40 楼 @reus

我也试了一下, go 的例子确实 100 多 ms。Linux arch 3.8.7-1-ARCH go1.0.3

犯了一个错。

#44 楼 @luikore 不不不…… 真相就是我没有创建 a.gt 文件 正确结果一个是 2s 一个 7s……

@reus @wendal 是我不好把文件没找到的错误扔掉了... 已经修改代码, 别忘了 a.gt 这个模板哦

#41 楼 @hhuai C/C++ 有一个很重要的优点:当标准库提供的某些组件在性能上不能满足需要时,我们可以再实现一个高效的 ;)

#41 楼 @hhuai 这就是比较丑的实现了, 而且不是 c++... 丑的实现不仅写起来慢, 而且容易出错

例如你的代码就有问题, 你可以试试 printf("%c",ss.p[0]); 看看能不能打出个减号

#50 楼 @luikore [] 只不过是个操作符而已,你喜欢的话重载就是, 嫌他丑,你可以把他包到库里,想多漂亮就多漂亮。 真正又有几个要靠 c++stl 那一套,从来都是自己按需求来实现,快不快,要看你的项目积累,稳不稳定看你的能力。

ps: 我和你讲性能,你就跟我讲丑,写起来慢。

@hhuai 楼主是在说 某些场景 下 ruby 的性能比 xx 好,而不是 ruby 性能比 xx 好

要追求性能,那还可以直接在 c 里写 asm,那么什么讨论都没有意义了

#52 楼 @jasl 我在反驳的就是楼主的例子,别断章,前面还有一页评论。 还有,不了解的人才以为手写 asm 能比 c 快。

#51 楼 @hhuai 你的代码是错的... 而且是常见错误: 把指针赋给了数组 (不要以为指针和数组是完全等价的...) 简单 fix 就是把 char p[1]; 改成 char* p;

另外就算 fix 了这个错误, 还有别的问题. 例如别人得到了你的这个字符串 b, 他怎么知道 b.p 能否 free? 最后还是编程者必须知道字符串的内部结构和生命周期, 全手动管理, 就和没有封装字符串这个 struct 一样.

字符串可以说是 C/C++ 世界里的亘古难题 (说是编程世界的难题都不为过), std::string 的包装就已经是 C++ 语法里能表示得最好的了... C++ 里要做 COW 的封装必须引入引用计数或者类似 GC 的机制, 否则只能暴露内部表示让编程者去 hack

@hhuai 第一个例子是 c++,string 是语言自身的数据类型,所以楼主用 Ruby 的 String 和 cpp 的 string 做对比,体现了 ruby 对 String 做了优化,而 cpp 的 string 的默认实现是没有的

而你反驳是用 c,这本身就是两码事了

@hhuai @luikore 我反感 cpp 的最大原因就是一个语言自身提供的机制里处处有坑,如 linus 说的,写的时候要时刻带着思想包袱,另外有类似感觉的是写 SQL 的时候

#55 楼 @jasl 对于 C++ 来说,string 只是 标准库的一个组件,不属于语言的内建类型,仅仅从语言层面来说,string 与其他自定义的 class 来说,无啥高低之分。 Ruby 的 String 则是 Ruby Core 的一部分。

@skandhas 唔。。。我没说清楚,标准库的实现我也包含在语言的范畴之内了

#57 楼 @skandhas 晕,感觉有时说得真累,又得跑回去扭基础知识。 luikore 先说我的代码是错的,指针不能付给数组。至于为什么要写成 char[1],我想写过 c 的人会懂的。

jasl 又说 string 是 c++ 的数据类型。至于例子用 c/c++ 表述其实是一样的

被你们完败了。

围观大神掐架,啥也看不懂

#59 楼 @hhuai char p[1]; 就是错的, 明显你对 C 太不熟悉了... 你可以试试

char p[1] = "hello world";
printf("%s", p);

有些版本的 c 编译器可以这么写:

char p[] = "hello world";

但是 char p[1] 就是不行

#35 楼 @hhuai 对的,有错误可以纠正,有问题可以反驳,但他说 “你这样有意思么”,这就真是喷了。

#56 楼 @jasl 可以说是坑,也可以说不是坑。 如果认真按照对的规则来写 C++的话,C++ 依然是生产力较高的语言。

我想说的是:有些规则太趋于细节,很多新手不注意的话,就会载进去。 在公司,想凑齐一队 C++ 水平不错且相当的人马,很难啊 Orz。

C++ 的入门曲线较陡,成长过程中,被碰出好几个脓包是很平常的 哈哈。但是如果跨过那个坎,后面就好很多了。只是跨坎的时间可能长点。平均来说,用 C++ 两年经验,只能算入门 ;(

我很同意游戏圈 云风 的一个观点:当项目是一个人做,用什么语言都可以,只要你能掌握好就可以。 但是如果项目是多个人合作,那么找齐一批 C++水平相当的高手可不容易。

我们公司有个项目有 近百万行(70 万行以上是有的)的 C++ 代码,有的模块实现的质量很高,有的模块却惨不忍睹。这就跟人跟团队的水平有关了。无奈阿。(当然,其他语言,当项目大了,人多了,差不多也是这个状况)

4 月份,我一直在做公司的培训,又负责 Effective C++的培训。我是真心的想把 C++的各个需要注意的坑都讲给他们, 但是效果一般啦,有些坑是需要自己跌过之后才记得住的,直接灌输,如果不经常练习,很快就会忘的。

我一直觉得 C++ 是一门很不错的语言,只是在一个公司内你很难找到和你一起来战斗的队友。在开源界就很好多了,C++ 高手很多的。可以互相学习和提高。

如果你爱一个人,就让他去学 C++,因为那里是天堂;如果你恨一个人,就让他学 C++,因为那里是地狱。泪奔啦。~~~

#59 楼 @hhuai c 和 c++ 就像 斯巴达和斯巴达克斯的区别吧...

说到 c 的话, 市面上任何一款 c 实现的 string, 只要是靠谱的 opaque type (封装隐藏了内部实现), 就不能 copy-on-write...

打个酱油, python 的 string 实现

typedef struct {
    PyObject_VAR_HEAD
    long ob_shash;
    int ob_sstate;
    char ob_sval[1];

    /* Invariants:
     *     ob_sval contains space for 'ob_size+1' elements.
     *     ob_sval[ob_size] == 0.
     *     ob_shash is the hash of the string or -1 if not computed yet.
     *     ob_sstate != 0 iff the string object is in stringobject.c's
     *       'interned' dictionary; in this case the two references
     *       from 'interned' to this object are *not counted* in ob_refcnt.
     */
} PyStringObject;

@skandhas cool 话说云风是 c++ 大牛转身成 c++ 黑的典型啊。。

#66 楼 @jasl 嗯 是阿。 在 weibo 上, 他与其他 C++牛的相互辩论也很有看头。只有思想的碰撞才会擦出耀眼的花火。象楼主这个帖子,给观众带来的收获就很大啦,各种观点的交流和沟通,比单纯的一个技术帖,收获还要多 ;)

#65 楼 @method_missing

PyStringObject 的话, 像下面这么写最多只能表示长度为 0-3 的字符串:

PyStringObject o;

一般这种 struct 必须整个用动态分配的, 像 #41 楼 那样写在栈上还是错的. @hhuai 的代码或者写成这样也可以:

string* ss = (string*)malloc(sizeof(string) + MALLOC_SIZE);
ss->length = MALLOC_SIZE;
memset(ss->p, '-', MALLOC_SIZE);

但这样就更不能 COW 啦.

#64 楼 @luikore 既然你明白那个是占位符的意思,为何又貌似不明白一样来纠结语法错误呢。

#70 楼 @bhuztez 如果是个人来学习的话,OK。如果是代替 C++来作我们公司开发语言的话,那老板就抓狂了!呵呵 ;)

#69 楼 @hhuai 哈哈哈哈哈 不要激动厄 为了提醒大家小心咯 像你这样的高手都会犯这样的错误,以免不明真相群众再次掉坑里啊 况且,你难道没看出来楼主讨论问题向来都是是很严谨的么 都是贴可以执行并且验证过的代码。而不是讨论一些像 “xx 不行了” “xx 和 oo 根本不在同一级别” 之类问题。

#72 楼 @diga2005 了解的人自然能看懂,我代码的意思也表达清楚了: 第一个例子只是在取巧,真正涉及到大内存,c/c++ 可以更灵活。

在 ruby 社区说 ruby 的确实存在的短处,自然会不受欢迎,但盲目的跟随与 YY,没必要吧。反正我不拜在哪个语言门下,只是一种兴趣,哪种好玩用哪种,当有了比较,自然就会吐槽一下。

同等水平的程序员,使用 rails 开发的话生产效率会高于其这语言。因为这会来带直接的效益。 这个理由足以使 80% 的公司来使用 ror。至于由于 ruby 性能较慢而导致的性能问题目前我还没有遇到过。 像 java 一样,ruby 也需要一个成长的过程。

合理的地方用合理的东西就行了,把各个部分分明白点,逻辑尽量封进 gem,不行就转做 c 呗,比这个不好玩。

看了这篇能了解不少东西。

不过某第一感觉其实这个是高级黑 Ruby 吧 XDDD

#61 楼 @luikore

我一直觉得 @hhuai C 很牛的... 虽然我目前并不懂 C.

@hhuai, 恕我妄言, 你别怪我哈! 我一直觉得你有个缺点, 就是编码习惯不太好, 因此再牛, 我估计也常常难免出错. 建议老兄看看 代码整洁之道 (马丁大叔写的), 还有, 花点时间, 用个好点的编辑器...

我觉得一般 c/c++ 性能和内存占用败下来基本上都是代码实现的问题。java 败给 c/c++ 没啥好说的,但性能败给动态语言和 php 这些,实际上还是败给了 c/c++,甚至是汇编。Go 现在很多优化还没做,库不够成熟,被欺负一下很正常 (好像 1.1 已经欺负不了了~~)。

#79 楼 @hooluupog 看情况的, 这里的特定情况就是 C++ 没 GC/引用计数 没法做 COW 的字符串抽象

另外虚拟机的一个作用是使用抽象程度高的字节码达到节省内存的目的, 有些 IC 卡上甚至能跑 Java, 但 C++ 运行时就载不进来.

Go 那个例子和优化没关系, Go 没有解释器所以只能在模板引擎里实现一个很原始的解释器, 比现代解释器差很远的. Go 如果要改进这块性能, 只能修改模板的处理方式, 把模板文件编译成 Go 源文件再进行编译, 否则永远也超不过 Ruby 的...

Go 一遍编译的速度已经没多少改进空间了, 但理论上, 虚拟机可以根据运行的 profile 动态修改代码, 能达到比没有虚拟机的语言更快的速度 (虽然现在的虚拟机都没达到这样的效果).

#76 楼 @AReverie 我也觉得楼主是在黑 Ruby.

性能不重要, 硬件发展才是王道.

#81 楼 @chai2010 高级黑,田忌赛马运用的相当了得

@luikore 记得 c++ 多数实现里 std::string 往往是 copy on write 似乎这样公平些..

#include <string>
#include <cstdlib>
#include <cstdio>

using namespace std;

int main (int argc, char const *argv[]) {
    string s(100000000, '-');
    string b = s;   # c++ copy
    printf("%lu\n", b.size());
    getchar();
    return 0;
}

或是都强制 COW. mem.rb

s = '-' * 100_000_000
b = s[1..-1]
b[0] = 'a'   # COW
puts b.size
gets

mem.cpp

#include <string>
#include <cstdlib>
#include <cstdio>

using namespace std;

int main (int argc, char const *argv[]) {
    string s(100000000, '-');
    string b = s;   # c++ copy
    b[0] = 'a';  #COW
    printf("%lu\n", b.size());
    getchar();
    return 0;
}
chenge Ruby 学习汇集,请推荐内容 提及了此话题。 07月04日 11:35
luikore 真的没必要浪费心思在 Go 语言上 提及了此话题。 05月09日 14:42
需要 登陆 后方可回复, 如果你还没有账号请 注册新账号