php與java

做者:eechen
連接:https://www.zhihu.com/question/20377398/answer/141328982
來源:知乎
著做權歸做者全部。商業轉載請聯繫做者得到受權,非商業轉載請註明出處。

PHP暫時還不支持像Java那樣JIT運行時編譯熱點代碼,可是PHP具備opcache機制,可以把腳本對應的opcode緩存在內存,PHP7中還支持配置opcache.file_cache導出opcode到文件.第三方的Facebook HHVM也支持JIT.另外PHP官方基於LLVM圍繞opcache機制構建的Zend JIT分支也正在開發測試中.在php-src/Zend/bench.php測試顯示,PHP JIT分支速度是PHP 5.4的10倍.
https://github.com/zendtech/php-src/tree/zend-jit/ext/opcache/jit
https://www.phpclasses.org/blog/post/493-php-performance-evolution.html

 


PHP的庫函數用C實現,而Java核心運行時類庫(jdk/jre/lib/rt.jar,大於60MB)用Java編寫(jdk/src.zip), 因此Java應用運行的時候,用戶編寫的代碼以及引用的類庫和框架都要在JVM上解釋執行. Java的HotSpot機制,直到有方法被執行10000次(-XX:CompileThreshold=10000)纔會觸發JIT編譯, 在此以前運行在解釋模式下,以免出現JIT編譯花費的時間比方法解釋執行消耗的時間還要多的狀況.

 

PHP內置模板引擎,自身就是模板語言.而Java Web須要使用JSP容器如Tomcat或第三方模板引擎.php

PHP內置HTTP服務器和SQLite數據庫,以及Apache模塊實現libphp.so和FastCGI服務PHP-FPM.而Java Web開發時廣泛須要使用第三方的Servlet容器Tomcat等.
PHP內置的單進程HTTP服務器(可用於快速開發和測試):
php -S 127.0.0.1:8080 -t /www

PHP-FPM跟Nginx同樣,是多進程的架構,worker進程處理請求,master進程不處理請求,只負責維護worker進程,好比定量重啓,崩潰重啓等.PHP-FPM支持進程池的特性,不一樣進程池相互隔離,互不影響.好比你能夠配置一個監聽9000端口的進程池www和一個監聽9001的進程池io來分離IO密集腳本:
nginx.conf: 訪問io.php的請求都交給監聽9001的PHP-FPM進程池處理
location = /io.php {
	include fastcgi_params;
	fastcgi_pass 127.0.0.1:9001;
	fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
php-fpm: 正常腳本由靜態www池處理,阻塞腳本由動態io池處理
[www]
;名爲www的進程池監聽9000端口,常駐進程數量爲固定4個
listen = 127.0.0.1:9000
pm = static
pm.max_children = 4
[io]
;名爲io的進程池監聽9001端口,進程數常駐4個,最大8個
listen = 127.0.0.1:9001
pm = dynamic
pm.max_children = 8
pm.start_servers = 4
pm.min_spare_servers = 4
pm.max_spare_servers = 4
其中I/O密集這個進程池[io]採用動態的prefork進程,好比這裏是繁忙時8個,空閒時4個.
利用PHP-FPM提供的池的隔離性,分離計算密集和I/O密集操做,能夠減小阻塞對整個PHP應用的影響.

也就是說,PHP經過多進程利用多核實現併發,而Java廣泛經過多線程實現併發,由於一個JVM實例就是一個進程.html

另外,PHP也能夠運行在多線程模式下,好比Apache的event MPM和Facebook的HHVM都是多線程架構.不論是多進程仍是多線程的PHP Web運行模式,都不須要PHP開發者關心和控制,也就是說PHP開發者不須要寫代碼參與進程和線程的管理,這些都由PHP-FPM/HHVM/Apache實現.java

PHP-FPM進程管理和併發實現並不須要PHP開發者關心,而Java多線程編程須要Java開發者編碼參與.PHP一個worker進程崩潰,master進程會自動新建一個新的worker進程,並不會致使PHP服務崩潰.而Java多線程編程稍有不慎(好比沒有捕獲異常)就會致使JVM崩潰退出.mysql

對於PHP-FPM和Apache MOD_PHP來講,服務進程常駐內存,但一次請求釋放一次資源,這種內存釋放很是完全. PHP基於引用計數的GC甚至都還沒發揮做用程序就已經結束了. 並且,在PHP腳本中用unset顯式釋放內存也是立竿見影的,不會有延時.而Java的內存回收嚴重依賴GC機制,高併發下的Full GC會致使Java服務雪崩:JVM忙於用GC回收內存沒法處理請求,而新請求又源源不斷地到來.nginx

PHP的運行模式決定了PHP自然支持熱部署,而Java要實現熱部署並不容易.這也是爲何在虛擬主機託管環境裏PHP佔絕對優點的緣由,由於開發者經過FTP上傳PHP文件到虛擬空間就實現了代碼更新和部署.git

PHP跨進程共享數據,除了使用基於文件的session機制和鳥哥開發的無鎖共享內存緩存擴展Yac.Linux上還可使用內存文件系統(tmpfs)上的SQLite(如/dev/shm/data.sqlite3).而Java程序的生命週期隨JVM常駐內存,線程能夠訪問共享數據.github

PHP不存在數據庫訪問速度比Java慢的問題.PHP的數據庫驅動如mysqlnd等都是C實現的驅動,而Java的數據庫驅動JDBC是Java實現的驅動,PHP的驅動性能並不吃虧.並且PHP一樣支持數據庫持久鏈接,也就是多個請求能複用一個數據庫鏈接,並不須要每一個請求都打開一個數據庫鏈接.好比下圖就是兩個PHP-FPM工做進程跟MySQL保持的兩個長鏈接:sql


PHP跟Java都誕生於1995年,沒有PHP相對Java是後起之秀的說法,反卻是PHP一開始就是用於Web開發,而Java不是.Java的前身Oak語言,是爲了嵌入式軟件開發而設計.

 

C實現的PHP後來吸取了C++的對象編程思想,加入了對象編程支持.既能夠用過程式,也能夠用對象,更靈活.而Java必須徹底面向對象編程,甚至還要把類名和文件名掛鉤.數據庫

PHP能不能開發大型應用,取決於使用者是否因地制宜地使用PHP. 好比,PHP就不適合用來開發數據庫引擎(大多都是C/C++實現)等計算密集型應用.Java在計算密集型應用上相比PHP更有優點,好比HBase數據庫使用了Java實現.不過大多數Web應用都是I/O密集型應用,這裏麪包括網絡I/O,文件系統I/O,數據庫I/O.apache

PHP是C實現的Web快速開發框架,不依賴第三方框架也能實現快速開發.而Java Web開發廣泛依賴Spring等第三方框架.

補充:
回覆

 

數據庫持久鏈接很容易用,mysqli裏host參數傳遞p:127.0.0.1就能開啓持久鏈接,pdo_mysql裏把PDO::ATTR_PERSISTENT設爲true也能夠開啓持久鏈接.並且PHP的數據庫持久鏈接也不依賴PHP-FPM,個人截圖不過是舉例說明,其實用Apache也同樣能夠.只是PHP-FPM的進程數或者Apache進程/線程數最好配置爲固定數量,並且要求數量不能超過MySQL最大鏈接數(max_connections默認是151).

進程間共享數據,除了Yac,我不是還說了Linux內存文件系統tmpfs上的SQLite麼?SQLite的鎖機制夠用了呀,連事務都支持,你擔憂什麼?並且內存上也不須要擔憂SQLite的讀寫性能限制,徹底是SQLite引擎在內存上的計算密集操做.能利用Linux的tmpfs機制,能利用SQLite的鎖機制,而不依賴PHP實現,我以爲頗有優點很穩定.

這裏討論的不是Swoole這類CLI下實現的PHP服務,而是PHP傳統的FastCGI模式.長時間後臺常駐運行的PHP腳本,固然須要GC.對於一些要求實時的高併發應用,我以爲就不該該使用GC機制.PHP能夠配置zend.enable_gc=off來禁用GC,而且本身經過unset來手動釋放內存.不過運行在FastCGI下的PHP腳本生命週期很短,其實原本就不依賴GC.再次強調,高併發實時類應用,GC毫不是一個優點,而是一個劣勢.

PHP常見的SAPI有這麼幾種:
php(cli,cli-server)
php-cgi(cgi-fcgi)
php-fpm/hhvm(fpm-fcgi)
libphp7.so/php7apache2_4.dll(apache2handler)
fpm-fcgi和apache2handler下,不管是多進程模式仍是多線程模式,進程和線程的實現和管理都不須要PHP開發者關心(這是優點),而是由php-fpm/hhvm/apache實現.PHP開發者若是要參與多進程或多線程編程,徹底能夠在php-cli下實現,相關PECL擴展包括pcntl多進程,pthreads多線程,libevent事件驅動等等,相關的項目實現有WorkerMan.另外峯哥的Swoole也須要用php-cli跑,但其服務的進程和線程控制也是由Swoole實現而不太須要PHP開發者關心.

PHP從5.4內置的單進程HTTP服務器,目的就是用於快速的開發和測試,我以爲是一個很方便的工具,開發者不須要安裝和配置Apache或者Nginx之類Web服務器就能進行入門開發.並且把PHP解釋器交叉編譯到Android手機或者OpenWRT無線路由就能用PHP這個省資源的HTTP服務器在局域網內編程並提供服務,很方便.

JIT在大量計算上有優點,bench.php腳本就是用來測試計算性能.真實應用如WordPress等,JIT能帶來的性能提高確定不會這麼明顯,具備JIT機制的HHVM和沒有JIT的PHP7,在壓力測試WordPress時體現出同一水平,就說明了這個問題.並且我強調過,Web應用大可能是I/O密集型應用,編譯型語言不會在I/O密集型應用裏也具備數量級的優點.因此說,對於大多數PHP開發者來講,就算是沒有JIT機制的PHP7,性能也夠用了.

回覆
mem php-fpm && siege -c10 -t1M http://www.example.com/app/punbb/index.php > /dev/null && mem php-fpm
其中mem是我定義在~/.bashrc裏的一個用於快速根據名稱查看程序狀況的函數:
mem () 
{ 
    top -n1 -b | head -n7 | sed '1,6d' && top -n1 -b | sed '1,7d' | grep --color=auto -i $1;
    ps aux | grep --color=auto -i $1 | grep --color=auto -v grep | awk -F " " '{ sum += $6 } END { printf "Total Memory Usage: %.1f MB\n", sum/1024 }'
}
測試程序PunBB是一個MySQL驅動的PHP輕量級論壇.
用siege併發10,壓測1分鐘,PHP-FPM工做進程的內存(RES)都是13.4MB,並不存在你所謂的PHP-FPM內存佔用會不斷隨請求數量而增加的問題,有圖有真相:
 

鄙人工做須要,兩種語言不斷切換,就簡單談一談二者區別

首先php確實是開發速度極快,爲何?由於弱類型(php7有類型聲明選擇開關,只要引入開關指令declare(strict_type=1)就會強制當前的文件下的程序遵循嚴格的參數類型,返回值類型),不須要定義返回的類型,加上php實際開發過程當中喜歡運用它萬能的數組來作計算,返回。因此他的動態擴展性很是強,若是返回值結構改變,不要緊,直接改數組結構就行(注意,php數組太強大,能夠看成map,list來用,底層的實現實際上是hashmap) 而java可能要開發過程可能要慢一點,java面向對象的技巧,設計模式會運用的更多一點。須要定義各種model來適應你業務的需求。編寫風格會有必定的統一要求。強類型在編寫的時候會比php麻煩,但好處是更安全,由於類型固定,潛在風險較低,還有編譯器給你作了一次保障。
相關文章
相關標籤/搜索