原文鏈接
分享:[分享] 大環境下瑟瑟發抖辭職的第二天,拿了兩個 offer
面試題解析
- 看你簡歷里也有用過 Go,Go 和 PHP 在運行的時候有什么區別和優勢?
題主原回答:
PHP 每個請求進來時都會創建 fpm-worker 進程,從而導致系統並發高時 CPU 會產生頻繁創建進程的開銷,而 Go 不會。
解析回答:PHP 每個請求進來時都會創建 fpm-worker 進程
補充下,這里 php 請求進來就會 由 PHP - FPM(php-fpm 是 php-cgi 的進程管理器)創建一個 PHP-CGI 進程來准備響
應用戶的請求。具體過程如圖,大家也可以繼續往下看詳細解析。
解析回答:而 go 不會
golang 是先編譯,后執行。 具體可以往下看詳細解析。
php 運行原理
目前常見的 4 種 PHP 運行模式
- CGI 通用網關接口模式
- FAST-CGI 模式
- CLI 命令行模式
- 模塊模式
CGI 通用網關接口模式
每有一個用戶請求,都會先要創建 cgi 的子進程,然后處理請求,處理完后結束這個子進程
cgi 是一種為了保證 web server 傳遞過來的數據是標准格式的通用網關接口協議
比較老,比較原始,大多已經不用了
FAST-CGI 模式
是 cgi 的升級版本,FastCGI 像是一個常駐 (long-live) 型的 CGI,它可以一直執行着,只要激活后,不會每次都要花費時間
去 fork 一次,也是一種協議
FastCGI 的工作原理是:
(1)、Web Server 啟動時載入 FastCGI 進程管理器【PHP 的 FastCGI 進程管理器是 PHP-FPM (php-FastCGI Process Manager)】(IIS ISAPI 或 Apache Module);
(2)、FastCGI 進程管理器自身初始化,啟動多個 CGI 解釋器進程 (在任務管理器中可見多個 php-cgi.exe) 並等待來自 Web Server 的連接。
(3)、當客戶端請求到達 Web Server 時,FastCGI 進程管理器選擇並連接到一個 CGI 解釋器。Web server 將 CGI 環境變量和標准輸入發送到 FastCGI 子進程 php-cgi。
(4)、FastCGI 子進程完成處理后將標准輸出和錯誤信息從同一連接返回 Web Server。當 FastCGI 子進程關閉連接時,請求便告處理完成。FastCGI 子進程接着等待並處理來自 FastCGI 進程管理器(運行在 WebServer 中)的下一個連接。在正常的 CGI 模式中,php-cgi.exe 在此便退出了。
在 CGI 模式中,可以想象 CGI 通常有多慢。每一個 Web 請求 PHP 都必須重新解析 php.ini、重新載入全部 dll 擴展並重初始化全部數據結構。使用 FastCGI,所有這些都只在進程啟動時發生一次。一個額外的好處是,持續數據庫連接 (Persistent database connection) 可以工作。
CLI 命令行模式
一般使用調用腳本、查看 php 信息時會使用到該模式
php -r”phpinfo ();” |less 分頁顯示
模塊模式
- Apache + mod_php
- lighttp + spawn-fcgi
- nginx + PHP-FPM
運行原理
PHP-CGI:fast-cgi 是一種協議,而 php-cgi 是實現了這種協議的進程。不過這種實現比較爛。它是單進程的,一個進程處
理一個請求,處理結束后進程就銷毀
PHP - FPM:是對 php-cgi 的改進版,它直接管理多個 php-cgi 進程 / 線程。也就是說,php-fpm 是 php-cgi 的進程管理器因此它也算是 fastcgi 協議的實現
php 的運行原理,就是在服務器啟動時,自動載入 PHP-FPM 進程管理器,從而管理多個 PHP-CGI 進程來准備響應用戶的
請求,如下圖所示:
多個運行模式相當於超市的不同入口,運行原理就是進入超市后的固定的行走路線,通過不同的運行模式進入到底層(進入超市)
golang 運行原理
golang 是先編譯為靜態二進制可執行文件,再去運行。
看看 go run 與 go build 的區別
go run 的執行過程
- 創建了兩個臨時文件夾 b001 和 exe
- 先執行了 compile 命令,然后 link,生成了歸檔文件.a 和 最終可執行文件
- 最終的可執行文件放在 exe 文件夾里面。
- 命令的最后一步就是執行了可執行文件。
舉個例子,生成的臨時文件可以用 go run -work
看到,比如當前生成的臨時文件夾是如下的路徑:
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
目錄,可以看到如下目錄結構:
可以看到,最終 go run 命令是生成了 2 個文件,一個是歸檔文件,一個是可執行文件。
go run 命令在第二次執行的時候,如果發現導入的代碼包沒有發生變化,那么 go run 不會再次編譯這個導入的代碼包。直接靜態鏈接進來。
go build 的執行過程
go build 用於編譯我們指定的源碼文件或代碼包以及它們的依賴包。但是注意如果用來編譯非命令源碼文件,即庫源碼文件,go build 執行完是不會產生任何結果的。這種情況下,go build 命令只是檢查庫源碼文件的有效性,只會做檢查性的編譯,而不會輸出任何結果文件。
go build 編譯命令源碼文件,則會在該命令的執行目錄中生成一個可執行文件,上面的例子也印證了這個過程。
go build 后面不追加目錄路徑的話,它就把當前目錄作為代碼包並進行編譯。go build 命令后面如果跟了代碼包導入路徑作為參數,那么該代碼包及其依賴都會被編譯。
go build 命令究竟做了些什么呢?我們可以執行 - n 這個命令來查看。 這里略過打印輸出。
執行過程和 go run 大體相同,唯一不同的就是在最后一步,go run 是執行了可執行文件,但是 go build 命令,只是把庫源碼文件編譯了一遍,然后把可執行文件移動到了當前目錄的文件夾中。
總結一下如下圖:
感謝關注
更多學習內容請訪問:
騰訊T3-T4標准精品PHP架構師教程目錄大全,只要你看完保證薪資上升一個台階(持續更新)