正则表达式引擎pcre使用JIT(即时编译)后比不使用速度快了好几倍(甚至10倍),为什么这么快?

原来就不慢,为什么还能提高这么多,哪方面提的速呢?

---把我下面的回复放上来,当作问题的补充---

因为pcre本身也是用c写的,并不是动态编译。我现在不明白的是它如何动态编译的,是分析二进制代码然后再重新编译?还是先运行一个虚拟机,再在上面跑,然后再分析?还有就是如何优化的?

最近一直再看pcre的源码(英文比较烂,看的慢,刚把未用JIT的代码看了个大概),觉得原来的代码并没有多少冗余,如果再打开c编译器的优化选项,觉得从代码本身来看并没有多大的优化余地,看了pcre的帮助文件也没说清楚原理,只说表达式里包含循环或者表达式越长用JIT的优化效果越明显,测试了确实如此。

再就是对这个比较感兴趣是也写过一个正则表达式引擎,速度和未用jit加速的pcre差不多,而且能优化的手段基本都用了,所以非常好奇jit是怎么优化的。

阅读 13.2k
2 个回答

我的理解是,你对PCRE JIT的理解错了吧。JIT的不是PCRE自身的C代码,而是PCRE里面那个正则表达式虚拟机的中间代码。既然你写过正则表达式引擎,那应该知道Virtual Machine Approach(http://swtch.com/~rsc/regexp/regexp2.html)。PCRE就是这种方式,
执行perl -e 'use re debug;/a|b/'会输出如下ByteCode(又称MIR - Middle Level Representation):

Compiling REx "a|b"
Final program:
   1: TRIE-EXACT[ab] (7)
      <a> 
      <b> 
   7: END (0)

而VM执行需要这样:

switch (byte_code) {
  case TRIE_EXACT:
    /*.....*/
}

JIT就是将这步省掉直接编译成机器码啊。尽管ByteCode已经够简单了,但这样执行仍然有免不了 switch、if这样的开销。将这此额外开销省掉大概能性能提升不少吧,剩下的只有read char和比较运算了。

静态编译优化和动态编译优化最大的不同是他们在编译时所得到的信息量的不同。静态编译在运行程序之前就把所有的执行代码编译完,这时编译器所接受的编译信息量是不够多的。比如说:某个函数是否是大量地被调用了,函数的实参是不是一直是一个常数,等等。

动态编译之于静态编译,缺点是它需要即时编译代码,但是有一个优点---编译器可以获得静态编译期所没有的信息。比如:通过运行时的profiling可以知道哪些函数是被大量使用的。在哪些execution
path上哪些函数的参数一直都没有变,等等。不要小看这些信息,当即时编译器了解这些信息之后可以在短时间内编译出比静态编译器更优质的二进制码。举例来说,一般程序也遵循90-10原则,即运行时的90%里计算机是在处理其中10%的代码,寻找到这些执行热点代码进行深度优化能得到比静态编译更好的性能(因为已知更多信息量)。

然而现实是:即时编译的开销非常大,暂时还不能超越静态编译的总体性能。不过,一个动态语言(如JAVA,Python)有着静态语言(如C++)所没有的各种优势,必然是将来程序语言发展的方向。伴随着强大的需求,即时编译器在将来也会更加强大。

在zhihu看到的
地址:
http://www.zhihu.com/question/19672491

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
宣传栏