如何用 Rust 来为 PHP 助力
上周,一篇关于《PHP 兼 Zend 联合创始人 Zeev Suraski 宣布从 Zend 离职》的文章在中国程序员中炸开了锅。文章中的Zend创始人离职可谓引起轩然大波,各种对PHP不友好的声音也被传递了出来。虽然来自中国的PHP核心开发者鸟哥发声,但许多程序员对PHP的态度并不是很乐观。
作为我在Web领域的入门语言,对PHP的感情犹如初恋一般美好。但伴随着近几年来大家对PHP各种调侃、讽刺,加上新语言Go、Rust、Javascript等强势崛起。似乎让“我是一名PHP程序员”变得底气很不足。来源于Web、辉煌于Web、受限于Web,不得不说,这让脚本语言PHP陷入了困境,因为Web已经不再是那个靠渲染网页的PC时代,虽然目前有Swoole这样优秀的异步方案,但也很难让我对PHP提起足够的兴趣。
Rust作为近几年来逐步流行的新兴语言,凭借安全、高效、可靠,开始进入了人们的视野。周末,重拾起了PHP,想看看是否能够在PHP和Rust之间擦出一点点火花。当然,只是出于个人兴趣做的一些实验,这并不能为两个优秀的语言带来什么改变。但我想,至少能够让大家对PHP和Rust有更多的了解。
PHP7.4中的FFI
起初,PHP7.4中的新特性FFI引起我很大的兴趣,因为在很多语言中已经拥有了这样的特性,例如:Python、NodeJS、Ruby等,PHP首次的引入,让我觉得PHP团队正在朝着这方面进行努力。
我首先采用Rust编写了一个Fibonacci斐波那契数列,这里实现了一个简单的计算函数,我将他导出为动态链接库,以供PHP的FFI调用。
- #[no_mangle]
- pub extern fn fib(n: i32) -> i32 {
- return match n {
- 1 | 2 => 1,
- n => fib(n - 1) + fib(n - 2)
- }
- }
编写完成后,我尝试在PHP的FFI中进行调用,为了想对比下性能,我同时编写了一个PHP的函数:
- // 一个PHP的fib函数
- function fib($n) {
- if ($n === 1 || $n === 2) {
- return 1;
- } else {
- return fib($n-1) + fib($n-2);
- }
- }
接下来,我在PHP中调用他们,为了能够看出性能差异,我将调用1000000次:
- // release模式
- $ffiRelease = FFI::cdef(
- "int32_t fib(int32_t n);",
- "r2p-fib/target/release/libr2pfib.$libExtension");
- $time_start = microtime(true);
- for ($i=0; $i < 10000000; $i++) {
- $v = $ffiRelease->fib(12);
- }
- echo '[Rust]Release执行时间:' . (microtime(true) - $time_start).PHP_EOL;
从测试结果来看,Rust的FFI结果是让人惊喜的。
PHP的计算耗时30秒以上,Rust仅仅用了6秒。
当我为此欣喜若狂的时候,我又尝试了下PHP的FFI调用生成字符串,在PHP中是类似这样一个方法:
- function text_generate($num) {
- $result = "