摘要:如下圖目錄結構主要針對的是非常駐內存方式運行,為了兼容,雖然做了很多優化,但是仍然無法像,等一些針對開發的框架一樣。在非常住內存框架中,為了方便會有一些寫法導致在常駐內存方式下不容易被釋放內存,小則內存泄漏,大則數據錯亂。
前言
ThinkPHP即將迎來最新版本6.0,針對目前越來越流行Swoole,thinkphp也推出了最新的擴展think-swoole 3.0架構分析
tp-swoole3.0不同于2.0版本,采用了全新的架構。(如下圖目錄結構)
tp主要針對的是非常駐內存方式運行,為了兼容swoole,雖然做了很多優化,但是仍然無法像swoft,sd等一些針對swoole開發的框架一樣。這里所說的不同,不是指tp不好,而是因為兩種模式都要兼容,不得不做出一些取舍。
請求分析該框架的運行機制,其實主要分析swoole的OnRequest函數即可,路由分發,數據處理等都是在函數處進行處理的。
Swoole.php
public function onRequest($req, $res) { $this->app->event->trigger("swoole.request"); $this->resetOnRequest(); /** @var Sandbox $sandbox */ $sandbox = $this->app->make(Sandbox::class); $request = $this->prepareRequest($req); try { $sandbox->setRequest($request); $sandbox->init(); $response = $sandbox->run($request); $this->sendResponse($sandbox, $response, $res); } catch (Throwable $e) { try { $exceptionResponse = $this->app ->make(Handle::class) ->render($request, $e); $this->sendResponse($sandbox, $exceptionResponse, $res); } catch (Throwable $e) { $this->logServerError($e); } } finally { $sandbox->clear(); } }
函數初始處,觸發了一個request事件,這里方便用戶自定義處理請求,進行一些定制化處理
$this->app->event->trigger("swoole.request");
重置請求,當是Websocket的時候,重置該類,具體為什么,下次我們分析Websocket的時候在進行解釋
$this->resetOnRequest(); protected function resetOnRequest() { // Reset websocket data if ($this->isServerWebsocket) { $this->app->make(Websocket::class)->reset(true); } }
接下來通過容器獲取沙盒,這里也是關鍵之處。在非常住內存框架中,為了方便會有一些寫法導致在常駐內存方式下不容易被釋放內存,小則內存泄漏,大則數據錯亂。而沙盒可以很好的解決這個問題。(文章最后會介紹一個造成內存泄漏和數據錯亂的案例)
$sandbox = $this->app->make(Sandbox::class);
請求進行預處理,這里進行的是request的轉換,從swoole的request轉換到tp的request
$request = $this->prepareRequest($req); $header = $req->header ?: []; $server = $req->server ?: []; if (isset($header["x-requested-with"])) { $server["HTTP_X_REQUESTED_WITH"] = $header["x-requested-with"]; } if (isset($header["referer"])) { $server["http_referer"] = $header["referer"]; } if (isset($header["host"])) { $server["http_host"] = $header["host"]; } // 重新實例化請求對象 處理swoole請求數據 /** @var hinkRequest $request */ $request = $this->app->make("request", [], true); return $request->withHeader($header) ->withServer($server) ->withGet($req->get ?: []) ->withPost($req->post ?: []) ->withCookie($req->cookie ?: []) ->withInput($req->rawContent()) ->withFiles($req->files ?: []) ->setBaseUrl($req->server["request_uri"]) ->setUrl($req->server["request_uri"] . (!empty($req->server["query_string"]) ? "&" . $req->server["query_string"] : "")) ->setPathinfo(ltrim($req->server["path_info"], "/"));
對沙盒進行設置,并初始化沙盒
$sandbox->setRequest($request); $sandbox->init();
啟動沙盒
$response = $sandbox->run($request);
如果發生異常,則將異常信息處理并發送
try { $exceptionResponse = $this->app ->make(Handle::class) ->render($request, $e); $this->sendResponse($sandbox, $exceptionResponse, $res); } catch (Throwable $e) { $this->logServerError($e); }
最終需要將沙盒信息清除
$sandbox->clear();
以上是tp-swoole對HTTP的處理流程,下文會詳細介紹沙盒的運行機制
番外篇 常駐內存易忽略的問題class A{ private static $intance=null; public static function getInstance(){ if (!empty(self::$intance)){ return self::$intance; } self::$intance = new static(); return self::$intance; } public static function clear(){ self::$intance=null; } public function echo(){ echo "echo"; } } $b = A::getInstance(); A::clear(); print_r($b->echo());
以上代碼會報錯嗎?
不會。仍然會輸出echo
下面在做另外一個實驗
class A { private static $intance = null; private $echo = "echo"; public static function getInstance() { if (!empty(self::$intance)) { return self::$intance; } self::$intance = new static(); return self::$intance; } public static function clear() { self::$intance = null; } public function echo() { echo $this->echo; } public function setEcho($echo) { $this->echo = $echo; } } $b = A::getInstance(); $a = A::getInstance(); $a->setEcho("b"); print_r($b->echo()); A::clear(); print_r($b->echo()); $a->setEcho("a"); print_r($b->echo());
以上代碼會輸出什么?
答案是:bba。那么為什么不僅沒有報錯,還輸出這樣的答案
PHP的變量對象引入是地址引用,當$a和$b被賦值時,他們所存的內容都是一樣的,且只有一份都是self::$intance位置所存放的內容。修改$a或$b都會修改self::$intance,那么為何當self::$intance為清除后,$a和$b仍然正常?基于PHP寫時復制,當self::$intance被清空,就會復制出來一份給$a和$b來使用。
當我們在非常住內存方式開發時,這些都不需要注意,因為每次請求都相當于一個多帶帶的線程,初始化所有數據,最后在將所有數據銷毀,且所有數據都是按照順序執行的。長住內存方式,就需要注意這些問題,不然會出現類似線程安全的問題。至于為何會出現這樣的問題,下文再敘。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/31641.html
摘要:由于是基于容器創建和銷毀資源的,那么各個容器之間是相對隔離的。也就是說每次請求都會創建一個新的環境用于執行和解析,由于容器的隔離性,每個請求都不會和其他請求進行干擾。因為只有當前協程才可以讀取到該數據。 前言 ThinkPHP即將迎來最新版本6.0,針對目前越來越流行Swoole,thinkphp也推出了最新的擴展think-swoole 3.0 沙盒 本文主要介紹在ThinkPHP-...
摘要:前言即將迎來最新版本,針對目前越來越流行,也推出了最新的擴展安裝由于目前沒有穩定版本,所以只能安裝開發板接下來安裝,目前最新的穩定版本是配置安裝結束可以根據自己的需求對配置信息進行修改。 前言 ThinkPHP即將迎來最新版本6.0,針對目前越來越流行Swoole,thinkphp也推出了最新的擴展think-swoole 3.0 安裝 由于目前thinkphp 6.0沒有穩定版本,所...
摘要:前言即將迎來最新版本,針對目前越來越流行,也推出了最新的擴展。介紹即將推出的,已經適配并推出,并且默認適配了。和版本在使用方法上面有些許不同。其中的第一個參數和的第一個參數一致,作為事件名稱。 前言 ThinkPHP即將迎來最新版本6.0,針對目前越來越流行Swoole,thinkphp也推出了最新的擴展think-swoole 3.0。 介紹 即將推出的tp6.0,已經適配swool...
摘要:安裝框架安裝如果已經安裝了可以跳過本步驟,但是請確定通過命令來確保已經使用了最新版本的使用以下命令可以直接通過官網下載并自動安裝到目錄下如果以上安裝過程極慢的話,可以嘗試用以下方式通過國內鏡像來安裝。 《當 Swoole 遇上 ThinkPHP5》:Hello,World! 本文假設你已經有了 Linux 操作系統的 PHP 環境,強烈推薦使用 Vagrant 來搭建開發環境 安裝 ...
摘要:文章目錄一線性模型二繪圖工具三作業一線性模型不要小看簡單線性模型哈哈,雖然這講我們還沒正式用到,但是用到的前向傳播損失函數兩種繪圖等方法在后面是很常用的。 文章目...
閱讀 3495·2021-11-12 10:36
閱讀 2875·2021-09-22 15:35
閱讀 2824·2021-09-04 16:41
閱讀 1174·2019-08-30 15:55
閱讀 3585·2019-08-29 18:43
閱讀 2079·2019-08-23 18:24
閱讀 1424·2019-08-23 18:10
閱讀 1928·2019-08-23 11:31