首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

如何用 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调用。

代码语言:javascript
复制
#[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的函数:

代码语言:javascript
复制
//?一个PHP的fib函数?function?fib($n)?{?????if?($n?===?1?||?$n?===?2)?{?????????return?1;?????}?else?{?????????return?fib($n-1)?+?fib($n-2);?????}?????}?

接下来,我在PHP中调用他们,为了能够看出性能差异,我将调用1000000次:

代码语言:javascript
复制
//?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中是类似这样一个方法:

代码语言:javascript
复制
function?text_generate($num)?{?????$result?=?"?";?????$result?.=?str_repeat("na?",$num);?????$result?.=?"Batman!??";?????return?$result;?}?

结果Rust由于在PHP的FFI中间字符串转换的损耗,性能并没有达到预想那样。

PHP扩展调用Rust动态库

因为第一个操作,让我想到了FFI在多次调用性能损耗是很大的,这时我想实现在PHP扩展中来调用Rust动态库。

同时为了对比,我编写一个C的Fib函数进行比较。

我创建了一个名为rust的PHP扩展,完成了关于我们上面编写的Rust函数的调用。

代码语言:javascript
复制
ZEND_BEGIN_ARG_INFO(arginfo_rust_fib,?0)?????ZEND_ARG_INFO(0,?number)?ZEND_END_ARG_INFO()??/*?{{{?int?rust_fib(?[?int?$var?]?)??*/?PHP_FUNCTION(rust_fib)?{?????zend_long?number?=?0;?????zend_long?result?=?0;?????ZEND_PARSE_PARAMETERS_START(0,?1)?????????Z_PARAM_OPTIONAL?????????Z_PARAM_LONG(number)?????ZEND_PARSE_PARAMETERS_END();??????if?(number?==?0)?{?????????RETURN_LONG(result);?????}?else?{?????????result?=?fib(number);?????????RETURN_LONG(result);?????}?}?/*?}}}*/?

结果同样让我惊喜,没有了FFI,它确实提升了20%左右的性能。但很明显,它的实现复杂度更高了。

采用Rust编写PHP扩展

将PHP的Zend API结构导出,直接在Rust中实现PHP模块的编写。虽然自己没有足够的精力去做这样的尝试,但我觉得这是一个可行的方法。我想在未来的时间内完成这样的尝试。

总结

虽然影响PHP更好的发展的主要因素并不是性能,尽管本篇只是从性能提升入手对PHP进行了测试,但我觉得,作为一个拥有如此庞大开发群体的Web语言,也是时候需要跟Go、Rust、Node这些新兴语言学习了,建立并不局限于Web领域的新的生态体系,大胆的去做一些新的尝试,让PHP不再是“世界第一语言”。

本文完整测试代码及结果请参考:https://github.com/llgoer/php-ffi-rust/

  • 发表于:
  • 原文链接http://news.51cto.com/art/201908/600739.htm
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

扫码

添加站长 进交流群

领取专属 10元无门槛券

私享最新 技术干货

扫码加入开发者社群
领券
http://www.vxiaotou.com