让Ruby性能增加30%的改进方法分析

开发 开发工具
我们都知道在编译Ruby的时候你需要使用configure的 --disable-pthread参数,而在configure --disable-pthread 可以让你得到大约 30% 性能提高。本文将分析这些性能的提高原因并给出更好的建议。

我们都知道在编译Ruby的时候你需要使用configure的 --disable-pthread参数。没错,在configure --disable-pthread 可以让你得到大约 30% 性能提高。但是,这是为什么呢?

所有的这一些我们需要使用 strace 工具,这个工具可以打出所有的真实的操作系统的调用。

下面,是一段我们测试的例程:

def make_thread
  Thread.new {
    a = []
    10_000_000.times {
      a << "a"
      a.pop
    }
  }
end

t = make_thread
t1 = make_thread

t.join
t1.join

如果我们使用 strace 工具去测试 configure --enable-pthread 版本的Ruby引擎,那么我们可以得到下面这样的结果:

22:46:16.706136 rt_sigprocmask(SIG_BLOCK, NULL, [], 8 ) = 0 <0.000004>
22:46:16.706177 rt_sigprocmask(SIG_BLOCK, NULL, [], 8 ) = 0 <0.000004>
22:46:16.706218 rt_sigprocmask(SIG_BLOCK, NULL, [], 8 ) = 0 <0.000004>
22:46:16.706259 rt_sigprocmask(SIG_BLOCK, NULL, [], 8 ) = 0 <0.000005>
22:46:16.706301 rt_sigprocmask(SIG_BLOCK, NULL, [], 8 ) = 0 <0.000004>
22:46:16.706342 rt_sigprocmask(SIG_BLOCK, NULL, [], 8 ) = 0 <0.000004>
22:46:16.706383 rt_sigprocmask(SIG_BLOCK, NULL, [], 8 ) = 0 <0.000004>

你会发现上面的sigprocmask 系统调用一页一页又一页地没完没了的。如果你用 strace -c,你会发现一共大约20,054,180 个sigprocmask系统调用。但是,如果你是在--disable-pthread 的Ruby版本下运行,你会发现根本没有那么多的sigprocmask 系统调用(只有 3 次,简直就是天壤之别)

查看一下源代码

我们知道 configure 是一个脚本,其主要用来创建一个 config.h 文件,其中有一大堆宏定义 defines ,这些宏定义决定了使用什么样的函数。所以,让我们来比较一下版本 ./configure --enable-pthread 和版本./configure --disable-pthread的不同之处吧。

$ diff config.h config.h.pthread
> #define _REENTRANT 1
> #define _THREAD_SAFE 1
> #define HAVE_LIBPTHREAD 1
> #define HAVE_NANOSLEEP 1
> #define HAVE_GETCONTEXT 1
> #define HAVE_SETCONTEXT 1

好的,现在我们再 grep 一下Ruby的源代码,我们可以看到只要HAVE_[S/G]ETCONTEXT 被设置了,Ruby 就会调用setcontext() 和getcontext() 这两个系统调用来存取context 的状态,以便异常处理时的切换(通过EXEC_TAG)。

而如果 HAVE_[S/G]ETCONTEXT 没有被定义 的情况下,Ruby 会使用 _setjmp/_longjmp这两个系统调用。

我们来看看 _setjmp/_longjmp 的man page:

… The _longjmp() and _setjmp() functions shall be equivalent to longjmp() and setjmp(), respectively, 
with the additional restriction that _longjmp() and _setjmp() shall not manipulate the signal mask…

还有setcontext /getcontext的 man page:

… uc_sigmask is the set of signals blocked in this context (see sigprocmask(2)) …

我们可以看到 getcontext 调用每次都要调用sigprocmask 但是_setjmp 不会。

补丁

通过补丁增加了一个configure 的参数 --disable-ucontext 其可以让你关闭使用 setcontext或getcontext,你只需要像如下方式使用就好了。

./configure --disable-ucontext --enable-pthread

补丁下载:http://github.com/ice799/matzruby/commit/0b9b69f9653782a33aee2b8937d405eae245b60c

如果你以这种方式编译Ruby,那么,你的程序的性能在同等条件下可能会有30%左右的提升。
 

【编辑推荐】

  1. Ruby语言的发展趋势和启示
  2. Ruby on Rails为企业SOA做好准备了吗
  3. 脚本语言排行榜 PHP、Ruby和Python领先
责任编辑:佚名 来源: 酷壳
相关推荐

2009-12-14 15:04:32

Ruby性能特点

2012-03-21 09:31:51

ibmdw

2009-08-06 11:12:17

提高GDI编程性能

2015-10-10 11:00:05

RubyRails性能

2015-10-14 17:27:18

性能

2009-12-14 13:56:12

Ruby特点

2010-01-27 15:17:50

2011-04-18 09:03:36

数据库查询

2009-06-29 18:04:13

Tapestry5

2020-01-07 10:14:38

Python程序员脚本语言

2009-12-16 15:23:33

Ruby on rai

2010-07-12 09:22:05

RubyRuby on rai

2023-02-17 12:55:39

RubyWebJava

2009-12-14 18:30:59

Ruby DSL特点

2009-12-17 14:47:21

Ruby优点

2015-01-21 15:40:44

GoRuby

2013-03-26 10:10:38

服务器RubyGo

2009-12-17 11:27:31

Ruby时间方法

2009-12-14 16:44:56

Ruby调用DLL

2009-08-18 22:15:38

VMware快照改进方
点赞
收藏

51CTO技术栈公众号