為何有些團隊更傾向于使用Go語言,而有些選擇PHP?
PHP的運行原理
目前常見的 4 種 PHP 運行模式
CGI 通用網(wǎng)關(guān)接口模式
FAST-CGI 模式
CLI 命令行模式
模塊模式
1. CGI 通用網(wǎng)關(guān)接口模式
每有一個用戶請求,都會先要創(chuàng)建 cgi 的子進程,然后處理請求,處理完后結(jié)束這個子進程。
cgi 是一種為了保證 web server 傳遞過來的數(shù)據(jù)是標準格式的通用網(wǎng)關(guān)接口協(xié)議。
2. FAST-CGI 模式
這個是 cgi 的升級版本,F(xiàn)astCGI 像是一個常駐 (long-live) 型的 CGI,它可以一直執(zhí)行著,只要激活后,不會每次都要花費時間去 fork 一次,也是一種協(xié)議。
FastCGI 的工作原理是:
1)、Web Server 啟動時載入 FastCGI 進程管理器【PHP 的 FastCGI 進程管理器是 PHP-FPM (php-FastCGI Process Manager)】(IIS ISAPI 或 Apache Module);
2)、FastCGI 進程管理器自身初始化,啟動多個 CGI 解釋器進程 (在任務(wù)管理器中可見多個 php-cgi.exe) 并等待來自 Web Server 的連接。
3)、當(dāng)客戶端請求到達 Web Server 時,F(xiàn)astCGI 進程管理器選擇并連接到一個 CGI 解釋器。Web server 將 CGI 環(huán)境變量和標準輸入發(fā)送到 FastCGI 子進程 php-cgi。
4)、FastCGI 子進程完成處理后將標準輸出和錯誤信息從同一連接返回 Web Server。當(dāng) FastCGI 子進程關(guān)閉連接時,請求便告處理完成。FastCGI 子進程接著等待并處理來自 FastCGI 進程管理器(運行在 WebServer 中)的下一個連接。在正常的 CGI 模式中,php-cgi.exe 在此便退出了。
在 CGI 模式中,可以想象 CGI 通常有多慢。每一個 Web 請求 PHP 都必須重新解析 php.ini、重新載入全部 dll 擴展并重初始化全部數(shù)據(jù)結(jié)構(gòu)。使用 FastCGI,所有這些都只在進程啟動時發(fā)生一次。一個額外的好處是,持續(xù)數(shù)據(jù)庫連接 (Persistent database connection) 可以工作。
3.CLI 命令行模式
一般使用調(diào)用腳本、查看 php 信息時會使用到該模式
php -r”phpinfo ();” |less 分頁顯示
4. 模塊模式
Apache + mod_php
lighttp + spawn-fcgi
nginx + PHP-FPM
運行原理
PHP-CGI:fast-cgi 是一種協(xié)議,而 php-cgi 是實現(xiàn)了這種協(xié)議的進程。不過這種實現(xiàn)比較爛。它是單進程的,一個進程處理一個請求,處理結(jié)束后進程就銷毀。
PHP-FPM:是對 php-cgi 的改進版,它直接管理多個 php-cgi 進程 / 線程。也就是說,php-fpm 是 php-cgi 的進程管理器因此它也算是 fastcgi 協(xié)議的實現(xiàn)。
php 的運行原理,就是在服務(wù)器啟動時,自動載入 PHP-FPM 進程管理器,從而管理多個 PHP-CGI 進程來準備響應(yīng)用戶的。Linux下php-fpm進程過多導(dǎo)致內(nèi)存耗盡問題解決
請求,如下圖所示:
多個運行模式相當(dāng)于超市的不同入口,運行原理就是進入超市后的固定的行走路線,通過不同的運行模式進入到底層。
教你用PHP爬取王者榮耀英雄皮膚高清壁紙(附源碼和壁紙)
Go語言的運行原理
golang 是先編譯為靜態(tài)二進制可執(zhí)行文件,再去運行的。
1. go run 的執(zhí)行過程
1 .go run 的執(zhí)行過程,如圖所示
創(chuàng)建了兩個臨時文件夾 b001 和 exe
先執(zhí)行了 compile 命令,然后 link,生成了歸檔文件.a 和 最終可執(zhí)行文件
最終的可執(zhí)行文件放在 exe 文件夾里面。
命令的最后一步就是執(zhí)行了可執(zhí)行文件。
舉個例子,生成的臨時文件可以用 go run -work 看到,比如當(dāng)前生成的臨時文件夾是如下的路徑:
localhost:hello ruby$ go run -work mytest.go
WORK=/var/folders/kt/nlhsnpgn6lgd_q16f8j83sbh0000gn/T/go-build593750496
HelloWorld
你好,Go!!!
localhost:hello ruby$
進入:/var/folders/kt/nlhsnpgn6lgd_q16f8j83sbh0000gn/T/go-build593750496 目錄,可以看到如下目錄結(jié)構(gòu):
可以看到,最終 go run 命令是生成了 2 個文件,一個是歸檔文件,一個是可執(zhí)行文件。
go run 命令在第二次執(zhí)行的時候,如果發(fā)現(xiàn)導(dǎo)入的代碼包沒有發(fā)生變化,那么 go run 不會再次編譯這個導(dǎo)入的代碼包。直接靜態(tài)鏈接進來。
2023年P(guān)HP/Go面試題集總結(jié)【建議收藏】
2. go build 的執(zhí)行過程
go build 的執(zhí)行過程,如下圖所示
go build 用于編譯我們指定的源碼文件或代碼包以及它們的依賴包。但是注意如果用來編譯非命令源碼文件,即庫源碼文件,go build 執(zhí)行完是不會產(chǎn)生任何結(jié)果的。
這種情況下,go build 命令只是檢查庫源碼文件的有效性,只會做檢查性的編譯,而不會輸出任何結(jié)果文件。
go build 編譯命令源碼文件,則會在該命令的執(zhí)行目錄中生成一個可執(zhí)行文件,上面的例子也印證了這個過程。
go build 后面不追加目錄路徑的話,它就把當(dāng)前目錄作為代碼包并進行編譯。go build 命令后面如果跟了代碼包導(dǎo)入路徑作為參數(shù),那么該代碼包及其依賴都會被編譯。
go build 命令究竟做了些什么呢?我們可以執(zhí)行 - n 這個命令來查看。 這里略過打印輸出。
執(zhí)行過程和 go run 大體相同,唯一不同的就是在最后一步,go run 是執(zhí)行了可執(zhí)行文件,但是 go build 命令,只是把庫源碼文件編譯了一遍,然后把可執(zhí)行文件移動到了當(dāng)前目錄的文件夾中。
面試題解析
面試官:看你簡歷里也有用過 Go,Go 和 PHP 在運行的時候有什么區(qū)別和優(yōu)勢?
回答:PHP 每個請求進來時都會創(chuàng)建 fpm-worker 進程,從而導(dǎo)致系統(tǒng)并發(fā)高時 CPU 會產(chǎn)生頻繁創(chuàng)建進程的開銷,而 Go 不會。
解析:PHP 每個請求進來時都會創(chuàng)建 fpm-worker 進程,這里 php 請求進來就會由PHP - FPM(php-fpm 是 php-cgi 的進程管理器)創(chuàng)建一個 PHP-CGI 進程來準備響應(yīng)用戶的請求。而 go不會,golang 是先編譯,后執(zhí)行。具體過程如圖
作為多年 PHP 的開發(fā)者,在使用了 Go 語言之后......
作者:碼農(nóng)編程進階筆記
歡迎關(guān)注微信公眾號 :碼農(nóng)編程進階筆記