如何用 Rust 来为 PHP 助力

llgoer
 llgoer
发布于 2019年08月04日
收藏 21

上周,一篇关于《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 = "💣";
	$result .= str_repeat("na ",$num);
	$result .= "Batman! 💣";
	return $result;
}

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

PHP扩展调用Rust动态库

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

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

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

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/

本站文章除注明转载外,均为本站原创或编译。欢迎任何形式的转载,但请务必注明出处,尊重他人劳动共创开源社区。
转载请注明:文章转载自 OSCHINA 社区 [http://www.oschina.net]
本文标题:如何用 Rust 来为 PHP 助力
加载中

精彩评论

南湖船老大
南湖船老大
垂死挣扎而已。
根本原因还是得从PHP底层改起,PHP底层设计太low了,其本质就是个C的模板引擎,很多或者说绝大多数PHP函数只是把C语言写的lib封装下,套一层皮而已,比如php的curl和curl命令行有99%的相似度。不要以为PHP把C封装了下离C最近性能就高,恰恰相反。

语言设计的最好的就是Java,把JVM和Java分开,JVM只使用少量C++/ASM代码实现和操作系统底层交互,并抽象出字节码。然后 Java语言依赖JVM,使用Java实现自举,比如常用的系统类以及javac,jconsole等JDK部分都是使用java语言来完成的。这样的好处是使用Java语言即可实现大部分功能(这在PHP里是无法想象的),比如要实现CAS或者多线程同步,只需要使用Java即可,而PHP则必须使用C语言来写个扩展,其复杂度复杂太多了。PHP里连一个strlen方法都需要依赖C写的方法来实现,实在是哭笑不得。Java的这种做法,丰富了Java的生态,并且基于JVM可以实现任意想要的DSL或新的语言,比如scala,coljure...

而PHP呢?屁大点功能都得依赖C这种没落的老古董实现一个扩展,然后用怪异的语法封装,再给PHP调用。

Go呢,也走了Java的路子,实现了静态语言的GC,也实现了自举,并且比 Java实现的更彻底。

你用PHP调rust,本质上改变不了PHP依赖C这个事实,一层套一层,性能不会有好的突破,只能实现一些玩具功能。至于swoole这个东西,更是救不了PHP。
高久峰是个大胖子
我最讨厌一种开发者,找工作找PHP岗位,上班也用不到GO,PHP都玩不好,各种数落PHP,推荐GO。一问问什么就给我说性能好,问题来了你做了几个项目需要性能好?当然我说的是哪些PHP都很菜的,PHP都写不稳的,PHP代码写的那么糟糕,你写GO能好到那里去???
回去干活
回去干活
废话说了一大堆 ,最后发现能快速实现 产品,为业务 服务的语言还是PHP。
然后什么性能牛B,直接编译本地代码的都是吹的很吊,最后发现一般项目跟本用不上。
南湖船老大
南湖船老大
PHP并没有开发效率优势。现在restful和app开发为主,那种程序和HTML混写的模式早就过去了。。后端只需要输出JSON即可,无论是Java的springboot还是go的gin框架,实现这些都是易如反掌。而且PHP现在的复杂度比以前复杂了不少,看起来是高级了,实际是复杂了,开发效率慢了。
不少互联网公司都从PHP转 Java了,比如杭州前两年最大的PHP用户贝贝网(淘宝就不说了),在17年左右转了。还有个很大的PHP用户小米也转Go了。现在唯一一个开倒车的是好未来,因为 swoole的作者去了好未来,开始转PHP了,我只能哈哈了。
__JM_Joy__
__JM_Joy__
传统PHP(fastcgi架构、apache模块或php-fpm)效率不高和应用场景受限的几个原因:
1.每次请求都将创建资源、处理请求、销毁资源跑一遍,造成性能浪费(opcache能缓解脚本文件读入和解析的压力)
2.没有可靠的连接池如数据库连接池、Redis连接池等,现成的方案坑比较多
3.没有异步编程和并行操作,线程扩展貌似用得不多。
4.无法实现长连接如websocket等协议,还有其他一些常驻内存的操作。

Rust要助力PHP的话可以从这几个点切入,我觉得PHP还能抢救一下。

最新评论(138

请问大家,php程序员和公司转什么比较合适? 我司主要做境外企业级咨询,实际就是中小型外包,目前以laravel+react为主,每年大家都有类似的转型讨论;

Go?不错,但是我们做的国际化应用多,在国外不太认可go(不用争论,go的确只在中国火),另外和php比,国外对性能要求不高,所以go对php,没有优势
Java?万能,但是不够潮?而且开发效率略低
python? 最近接了很多ai方面的咨询,客户对Python 也比较buying,但是如果单纯做web,和php比没有绝对优势,不确定值不值得。

目前国外流行的模式是api+react
有考虑过转js全栈,但是对node.js的服务稳定性有所顾忌;还考虑过graphsql,但是小众一点。

希望大家能够帮助分析分析。 1. 开发效率高;2.不考虑性能,几个客户国家总人口才几千万;3. 前端是react.js,实际更多考虑api
团队可能要做一定的大数据Ai方面技术积累,但是本身能力一般,考虑学习曲线问题
目前来看,貌似java最万精油。各方面比较平衡;还请各位大佬给个建议。
缺Q德
缺Q德
PHP最主要还是现在多app化 传统的网站不像以前那么~~~
Keijack
Keijack
现在不要说PHP,Java 写个 J2EE 都被鄙视了,现在都流行前后端分离,微服务化!现在的选择都不是那种适合就好的年代了,特别是那些小公司,都选看起来好像很高大尚的技术。
不灭的焱
不灭的焱
最讨厌那种人: 用着 PHP,还满大街说PHP的各种不是。。。装着很懂的样子。。。你有能力就开发出 属于中国人 自己的开发语言,形成生态
johngcn
johngcn
没有什么银弹,适合的就好
Strutsz
Strutsz
每款语言都有他的优点和缺点,优点就是敏捷开发,缺点就是漏洞太多,所以我们不要太在意用什么,看项目情况而定,能给企业带来收益才是硬道理。
平原君
平原君
PHP的性能劣势导致在大型应用上不是Java的对手,至于快速开发,我现在觉得nodejs更好,前后一统写着还是挺爽的。
Strutsz
Strutsz
java现在不行了.net core 比java好多了毕竟是c的儿子
花间一壶酒___
大家都在喷java写不了操作系统,那以前的java手机算不算?性能好不好?
st_lein
st_lein
塞班也是C写的吧,只是支持J2ME而已
花间一壶酒___
还有大量非塞班系统,无操作系统的
我爱吃炒鸡
我爱吃炒鸡
算了,我用go了
回去干活
回去干活
废话说了一大堆 ,最后发现能快速实现 产品,为业务 服务的语言还是PHP。
然后什么性能牛B,直接编译本地代码的都是吹的很吊,最后发现一般项目跟本用不上。
高久峰是个大胖子
是啊 大部分公司哪有那么多并发 开发速度和性能肯定要有原则
左华栋
左华栋
大公司要考虑维护,主要是架构和分层的问题....这些都不是PHP擅长的....
所以事实是国外几乎没有大公司用php了,哦对了,facebook 是 Hack
高久峰是个大胖子
嗯。我是说大部分公司。大公司技术栈必然是多样性的。
仙士可
架构分层考验的是程序员,而不是语言
国外没有大公司用,那你去国外不就行了,在国内扯这些有的没得有什么用
技术栈是多样性的,存在即合理,论web领域,没人干的过php
左华栋
左华栋
web 市场也在萎缩。
前后端分离,微服务是趋势...这点上php并没有优势
仙士可
微服务,前后分离,这是程序员的问题,语言只是实现的工具,这个哪来优势一说?写个逻辑还有优势了?
左华栋
左华栋
node.js 和 springboot 也一样开发效率很高,性能也好,能做得事情更多,并且拓展安装还没那么麻烦...并且后期做微服务也更适合。何必吊死在一颗逐渐失去市场的语言呢?
仙士可
你说的效率高有多高?一个礼拜写一个登陆注册吗?有没有失去市场不是你这个php菜鸡说了算的
宝塔一键安装lnmp你懂吗
左华栋
左华栋
说宝塔你是在黑php环境难装,所以需要一键安装包?
实际上,主流编程语言都不需要一键安装包...只有php...
登录注册springboot 用现成的也行,自己搞的话2个小时也能搞定。效率差不多的。而且现成的库很全
仙士可
那只能说明你不懂php而已,lnmp是全局web环境,lnmp包含了mysql,nginx,php只是一个而已,不知道你有没有听过php-cli,要是安装纯php,自己编译的话10分钟就能搞定,yum安装就更快了,登陆注册,各种业务,php的源码数不胜数,自动生成curd.半小时一个站.
返回顶部
顶部