龙空技术网

如何让 PHP 快 2000 倍

启辰8 2757

前言:

如今各位老铁们对“phpapache调试”大约比较注重,你们都想要学习一些“phpapache调试”的相关文章。那么小编在网络上网罗了一些对于“phpapache调试””的相关资讯,希望各位老铁们能喜欢,兄弟们快快来了解一下吧!

我们将讨论为什么 PHP 是一种很棒的编程语言,如何使您的应用程序在性能和开发方面更快。

为什么 PHP 是一种很棒的语言?它很可靠,— 您安装它就可以工作。它是稳定的——在主要版本之间更新需要对代码进行少量更改,并带来性能提升和新功能的喜悦,为 PHP 创建库的开发人员以及您在堆栈溢出中找到的解决方案也继承了这一点。它专为 Web 设计,内置模板、抓取、正则表达式、JSON、XML、各种数据库和 Web 服务器支持,并且在发明之前就具有服务器端渲染 (SSR)。它受支持——查看流行的 CMS 列表——它们大多是用 PHP 构建的,请参阅供应商网站上的插件:Shopify、Stripe、Twilio 和其他供应商都有 PHP SDK。它功能丰富,支持最新技术:Docker、NoSQL、WebSockets、多租户、图像处理、外部函数接口、Laravel 等框架、前端和后端单一语言等等。速度呢?

为什么我没有提到 PHP 很快?让我们首先定义快速对于 Web 开发意味着什么。根据我的经验,Web 应用程序的瓶颈是数据库,那么除了说“Hello,world!”之外,语言的响应速度有多快?有语法错误不是你应该比较的东西。

有一些简单的方法可以让您的 Web 应用程序运行得更快——购买更强大的服务器。即使有像HostZealot这样的伟大托管公司,它可以让您以可承受的价格获得高性能的专用服务器,也有像Cloudflare这样的公司可以通过减少机器人和爬虫造成的负载来节省服务器的 CPU 和 RAM,改进在应用程序源中可以为您带来更令人印象深刻的结果。

对于作为开发人员的我来说,在选择最喜欢的语言时,浪费在寻找可行解决方案、调试和编译上的时间是最重要的。

因此,让我们看看在快速应用程序开发方面我们可以改进什么。

什么比前端和后端更好?

Web 应用程序开发的当前趋势是使用前端和后端应用程序。从 2 名程序员分担工作的角度来看,这很好:一个应该知道如何有效地使用数据库和第三方 API,另一个应该知道如何构建精美的界面。

这种方法有什么问题?

当应用程序进入维持阶段时,您开始寻找需要像上面提到的两个人一样工作的全栈开发人员。构建 2 个应用程序并将它们与 API 集成不会给您带来价值,但根据我的经验,它通常会带来威胁:例如,您有一个 API 可能会错误地允许从您的数据库中读取您不想共享的数据如果未明确禁止,您的竞争对手可能会获取您的用户电子邮件。花哨的界面会增加您的应用程序的大小,您的用户需要等待很多时间,而Google 会在搜索排名中考虑到这一点。我有优化 node.js 应用程序的经验,它有 1.6 GB 的库,页面加载时间超过 6.5 秒,编译需要几分钟。Node.js 是编译的意思,是吃开发者的时间。JavaScript 被设计为无需编译即可运行,但 node.js 带回了过去,为了弥补这个问题和它带来的其他问题,发明了很多东西:热模块替换 (HMR)、服务器端渲染 (SSR)、编译器用 Go 等编写,其中在另一个应用程序设计中不需要它们,它们通常不稳定。

是否有另一种解决方案可以带来更多利润?想象一下,您可以在单个应用程序中编写后端和前端部分,甚至可以使用相同的语言编写现代交互式应用程序。这就是 Laravel Livewire框架让你拥有的。

在创建全栈应用程序时,Laravel 并不是唯一允许这种方法的框架。如果您足够开放,可以尝试使用 Elixir 编程语言及其 Phoenix 框架和LiveView模板。

什么时候语言速度很重要?

如果您的应用程序大量使用数学,例如它是图像或视频处理应用程序、压缩或加密算法、3D、加密货币或 AI 应用程序,那么您肯定对一种语言感兴趣,这种语言可以构建最有效地使用 CPU 和 RAM 的应用程序。

PHP 不擅长这里,它需要 40 个字节来存储一个数组中的一个整数,这使得上面提到的算法运行起来非常慢。

这里显而易见的解决方案是选择另一种语言。

您绝对不想在 Assembler 中编写或多或少复杂且可持续的应用程序,但您有哪些选择?Fortran 很快,但它是非常小众的语言,C++ 很棒,但它有时太强大了,很容易造成内存泄漏。在快速的现代语言中,有 Mozilla 开发的 Rust 和谷歌开发的 Go,其中Rust 在计算分形方面胜出。

如何让PHP擅长数学?

“等等,你说你可以让 PHP 运行得更快!” ——你会说。

是和不是。我们将使 PHP 应用程序运行得更快,方法是使用一个库来执行 CPU/RAM 密集型操作,该库是用一种更适合该应用程序的语言编写的。

这样做有多种选择:

您可以编写一个应用程序并使用 shell_exec() 函数执行它,如果您需要运行一次大型应用程序,这是合适的。您可以编写一个 PHP 扩展并将其包含到 PHP 中,如果您想为社区提供您的功能,这非常有用。使用外部函数接口(FFI) 来包含库(Linux 的 .so、Windows 的 .dll 或 MacOS 的 .dylib)。外部函数接口 (FFI)

FFI 是让 Python 如此流行的原因。它允许将任何库包含到您的应用程序中并使其功能可用。例如,要在 Python 中创建桌面应用程序,您可以使用 PyQt 库,它实际上不是库本身,它是对Qt 库的绑定。

在 PHP 中,此功能于 2018 年底在 PHP 7.4 中引入。

与等待库供应商创建 PHP 扩展相比,我相信您已经了解使用 FFI 的好处。由于优秀的 PHP 文档和社区,与编写自己的 PHP 扩展相比,它并没有复杂得多,但它在心理上仍然更简单。

实例

包含一个实例,因此您可以自己动手做并提高性能。

准备基础设施

您无法像我一样想象在不使用 Docker 的情况下开发 Web 应用程序,对吧?:)

我们不会在您的机器上安装 PHP 或 Rust,相反,我们将使用最简单的方式在 Docker、docker-compose 和官方 PHP+Apache docker 镜像中运行 PHP 。

使用以下内容在项目文件夹中创建 docker-compose.yml 文件:

version: '3.5'services:  php:    container_name: php_2000x_faster    build:      context: .      dockerfile: Dockerfile    ports:      - 5080:80    volumes:      - './app:/var/www/html'      - './mylib:/var/www/mylib'

在您的项目文件夹中创建包含以下内容的 Dockerfile 文件:

FROM php:8.2-apache# Installing Rust.RUN apt-get update &&\    apt-get install -y cargo# Installing OPcache.RUN set -eux; \    docker-php-ext-configure opcache; \    docker-php-ext-install opcache;# Enabling OPcache and JIT.RUN echo "opcache.enable=1" >> $PHP_INI_DIR/conf.d/opcache.ini &&\    echo "opcache.jit=on" >> $PHP_INI_DIR/conf.d/opcache.ini# Installing FFI.RUN apt-get update &&\    apt-get install -y libffi-dev &&\    docker-php-ext-configure ffi --with-ffi &&\    docker-php-ext-install ffi# Configuring FFI to preload a given file.RUN echo "ffi.enable=preload" > $PHP_INI_DIR/conf.d/ffi.ini &&\    echo "opcache.preload=/var/www/html/preload.php" >> $PHP_INI_DIR/conf.d/ffi.ini# WARNING! For development purposes only.# Making www-data user match your user to be able to edit files mapped from your local system.RUN usermod -u 1000 www-data# Setting a user to be default apache user.USER www-dataENV USER=www-data# Running.CMD echo 'Building a library.' &&\    # TODO: uncomment when library is created.    # cd /var/www/mylib &&\    # rustc --crate-type=cdylib -O -o ./mylib.so ./src/lib.rs &&\    echo 'Starting apache' &&\    apache2-foreground

为您的项目创建文件夹。

mkdir appmkdir mylib

通过在项目文件夹中运行来启动 docker 容器:

docker-compose up --build
创建一个 Rust 库项目

现在我们已经安装了所需的依赖项并可以创建一个 Rust 项目。

docker exec php_2000x_faster cargo init ../mylib

如果你想在你的存储库中同时拥有这两个应用程序,请删除 git 文件夹。

docker exec php_2000x_faster rm -rf ../mylib/.git

库文件默认命名为 lib.rs,让我们在 mylib/src 文件夹中创建这个文件。它将包含简单的、深受程序员喜爱的斐波那契数计算函数以及允许运行多次斐波那契函数的函数,我们将在下面用于基准测试:

#[no_mangle]pub extern fn fibonacci(number: i64) -> i64 {  return match number {    0 => 0,    1 => 1,    number => fibonacci(number - 1) + fibonacci(number - 2)  }}#[no_mangle]pub extern fn fibonacci_loop(repeat: i64, number: i64) -> i64 {  let mut result = number;  for _ in 0..repeat {    result = fibonacci(number);  }  return result}

现在您可以取消注释 Dockerfile 中的以下行以启用编译库:

...# Running.CMD echo 'Building a library.' &&\    # TODO: uncomment when library is created.    cd /var/www/mylib &&\    rustc --crate-type=cdylib -O -o ./mylib.so ./src/lib.rs &&\    echo 'Starting apache' &&\    apache2-foreground
将 Rust 库导入 PHP 应用程序

我们已经为 PHP 启用了 FFI,我们还指示 OPcache 从 app 文件夹中的 preload.php 文件预加载一个库。我们需要做的是使用这种机制导入库。

在 app 文件夹中创建 preload.php 文件,内容如下:

<?phpFFI::load(dirname(__DIR__) . "/mylib/mylib.h");opcache_compile_file(__DIR__ . "/mylib.php");

重要的是你需要描述你的库的 C 头文件,这个文件包含我们将要使用的函数的定义。为此,在 mylib 文件夹中创建 mylib.h 文件,内容如下:

#define FFI_SCOPE "MyLib"#define FFI_LIB "./mylib.so" int64_t fibonacci(int64_t n);int64_t fibonacci_loop(int64_t total, int64_t n);

剩下的就是创建一个将使用该库的类。为此,在 app 文件夹中创建 mylib.php 文件,内容如下:

<?phpfinal class MyLib {    private static $ffi = null;    function __construct() {        if (is_null(self::$ffi)) {            self::$ffi = FFI::scope("MyLib");        }    }    function fibonacci($number) {       return (int)self::$ffi->fibonacci($number);    }    function fibonacci_loop($repeat, $number) {       return (int)self::$ffi->fibonacci_loop($repeat, $number);    }}

我们将使用这个类来运行 Rust 库中的函数。

运行基准

在 app 文件夹中创建 index.php 文件,内容如下:

<?phpfunction fibonacci($number) {    if ($number == 0) {        return 0;    } elseif ($number == 1) {	  return 1;    } else {        return fibonacci($number - 1) + fibonacci($number - 2);    }}function fibonacci_loop($repeat, $number) {    $result = 0;    for ($i = 0; $i < $repeat; $i++) {        $result = fibonacci($number);    }    return $result;}require_once "mylib.php";$myLib = new MyLib();echo '<pre>';$repeat = 50;$number = 32;$startTime = microtime(true);$myLib->fibonacci_loop($repeat, $number);$executionTimeRust = microtime(true) - $startTime;echo "Running fibonacci number calculation $repeat times for $number number."."\n";echo "Fully on Rust execution time: <strong>$executionTimeRust</strong> sec."."\n";$startTime = microtime(true);for ($i = 0; $i < $repeat; $i++) {     $myLib->fibonacci($number);}$executionTimeRustPhp = microtime(true) - $startTime;echo "Calling Rust function in PHP loop execution time: <strong>$executionTimeRustPhp</strong> sec."."\n";$startTime = microtime(true);fibonacci_loop($repeat, $number);$executionTimePhp = microtime(true) - $startTime;echo "Fully on PHP execution time: <strong>$executionTimePhp</strong> sec."."\n";$boostFactor = $executionTimePhp/$executionTimeRust;echo "Total boost: <strong>$boostFactor</strong> times." . "\n";        echo '</pre>';

停止并重启 docker 容器:

Ctrl+Cdocker-compose up --build

在 Web 浏览器中打开应用程序您将看到以下内容:

结论

如您所见,用 Rust 重写 CPU 密集型计算可使性能提高 2000 倍以上。正如我上面提到的,PHP 不是非常适合大型数组,例如为图像处理制作自定义算法,因此在这里您也可以获得很大的好处。

请注意 rustc 命令中的 -O 选项非常重要,因为没有它它会生成运行极其缓慢的未优化代码。

标签: #phpapache调试