PHP使用swoole/workman让框架常驻内存的原理以及自己实现常驻内存的演示

1.PHP的生命周期

PHP有多进程版本和多线程(TSRM)版本,它们的生命周期如下:

多线程版本-图片来源: http://www.phpinternalsbook.com/php7/extensions_design/php_lifecycle.html
多进程版本-图片来源: http://www.phpinternalsbook.com/php7/extensions_design/php_lifecycle.html

整个PHP的生命周期如下:

图片来源: http://www.phpinternalsbook.com/php7/extensions_design/php_lifecycle.html

流程为:

1.模块初始化(1.GINIT()全局资源初始化2.MINIT()模块初始化)

2.请求处理(1.请求初始化2.处理请求3.释放请求资源)

3.释放模块资源,释放全局资源

2.如何做到常驻内存?

很简单,只要让脚本不退出,资源自然不会释放。而swoole和workman使用了内置的webserver,它们都是阻塞监听正常情况下永远不会退出的 php-cli脚本,所以每次客户端请求过来的时候,可以直接使用常驻内存中的框架代码处理请求,而不用像PHP-FPM一样,每次都要重新初始化资源,执行脚本完以后再释放资源。

3.常驻内存做法的弊端

对于每次请求,不会重新初始化和释放资源,导致很多资源处于常驻状态。每次请求这些资源实际上访问的都是上一次请求所处理的结果。如果你的类里有成员变量,你对成员变量的操作++–的结果都会保留到下一次请求中,另外session的生命周期也被破坏,每次请求过来,获取的session都是上一次请求的session,所以我们需要自己维护session的周期(每次请求需要设置session_id),或者不用session,放redis里也可以,通过onclose回调可以主动释放部分资源。

4.代码演示

<?php

class WebServer
{

    public $onRequest;

    public function __construct()
    {

    }

    public function run()
    {
        $socket = stream_socket_server(
            'tcp://0.0.0.0:7777',
            $errno,
            $errstr
        );

        if (!$socket) {
            echo "$errstr ($errno)" . PHP_EOL;
        } else {
            while ($conn = stream_socket_accept($socket)) {
                $response = '';

                if ($this->onRequest) {
                    $response = call_user_func($this->onRequest, $conn);
                }


                $responseheader = $httpResponse = "HTTP/1.1 200 OK\r\n";

                $responseheader .= "Content-Type:text/html;charset=utf-8\r\n";

                $responseheader .= "Content-Length: ".strlen((string)$response). "\r\n\r\n";

                fwrite($conn, $responseheader.$response);

                fclose($conn);
            }
        }
    }

}

class A
{
    private $a;

    public static $static_a;

    public function __construct()
    {
        session_start();
        $_SESSION['a'] = 1;
    }

    public function plusA()
    {
        $this->a++;
        static::$static_a++;
    }

    public function getA()
    {
        $res = 'none-static:' . $this->a . PHP_EOL;
        $res .= 'static:' . static::$static_a . PHP_EOL;

        return $res;
    }
}

$a = new A();

$server = new WebServer();

$server->onRequest =  function($conn) use($a) {
    $a->plusA();

    return $a->getA() . 'session:' .$_SESSION['a'] . PHP_EOL;
};

$server->run();

这里不考虑高性能,直接演示一个最基础的套接字模型。

两个浏览器不同的session访问的结果都一样
这是workman里的效果
如无特殊说明,文章均为本站原创,转载请注明出处。如发现有什么不对的地方,希望得到您的指点。

发表评论

电子邮件地址不会被公开。 必填项已用*标注