各種語言的併發原理整理

NodeJs嚴格來說不是一門語言而是一個運行於服務端的JavaScript解釋器。Node.js是一個基ChromeV8引擎的JavaScript運行環境,一個讓JavaScript運行在服務端的開發平臺,實質是對Chrome V8引擎進行了封裝。V8 JavaScript引擎是由Google公司使用C++語言開發的一種高性能JavaScript引擎,該引擎並不侷限於在瀏覽器中運行。類似我們在使用PHP和Python時需要安裝的運行環境一樣的道理。

Node 使用事件驅動 非阻塞I/O 模型而得以輕量和高效,非常適合在分佈式設備上運行數據密集型的實時應用。在Java、PHP或者.NET等服務器語言中,會爲每一個客戶端連接創建一個新的線程,而每個線程需要耗費大約2MB內存,也就是說,理論上一個8GB內存的服務器可以同時連接的最大用戶數爲4000個左右。要讓web應用程序支持更多的用戶,就需要增加服務器的數量,而web應用程序的硬件成本當然就上升了。

NodeJs不爲每個客戶連接創建一個新的線程,而僅僅使用一個線程。當有用戶連接了就觸發一個內部事件,通過非阻塞I/O事件驅動機制讓Node.js程序宏觀上也是並行的。使用Node.js一個8GB內存的服務器,可以同時處理超過4萬用戶的連接。

PHP(外文名:PHP: Hypertext Preprocessor,中文名:“超文本預處理器”)是一種通用開源的、簡單的、面向對象的、解釋型的、健壯的、安全的、性能非常之高的、獨立於架構的、可移植的、動態的腳本語言。PHP語法吸收了C語言、Java和Perl的特點,利於學習,使用廣泛,主要適用於Web開發領域。PHP 獨特的語法混合了C、Java、Perl以及PHP自創的語法。它可以比CGI或者Perl更快速地執行動態網頁。php的解釋器是zend,zend是用c語言寫的,zend將PHP翻譯成c語言,然後再編譯成機器碼,這時候機器才能執行。這就是php的底層是c的由來。

Python 是一種解釋型、面向對象、動態數據類型的高級程序設計語言。Python和PHP類似也有自己的解釋器,常見的解釋器是C語言編輯的,所以也稱CPython,還有Python自己實現的解釋器pypy。Python社區的標準是CPython實現,是C語言寫的。

協程

在操作系統當中有兩種概念,一個是進程,一個是線程。進程擁有獨立的資源空間,也就是各個進程之間不共享資源,操作系統爲了能夠讓多個進程“同時”運行,採用了時間片輪換機制,CPU某一時刻屬於一個進程,下一時刻就切換到另外一個進程,當時間片足夠短的時候,我們就可以感覺到多個進程同時運行。

因爲進程之間不共享資源,切換的代價就會比較的高,所以後來就設計了線程。一個進程可以含有多個線程,各個線程共享一個進程中的資源,線程的切換隻是切換CPU中的執行代碼,運行時所需要的資源幾乎可以不用切換,大大提高了切換效率。

其實線程也有自己獨立的資源,比如運行時創建的堆棧信息等,一般線程初始化的時候會預分配1M左右的空間用於存放這些資源,所以切換依然是有成本的。

目前比較流行的一種更加高效的方式是協程,協程是以多佔用內存爲代價,實現多任務的並行的,協程有多線程版本的也有單線程版本的

以Nodejs爲例來說(js是單線程的),nodjes中的協程其實是多個可以並行執行的函數的協作。怎麼來理解這句話呢?傳統的程序執行採用堆棧式的執行方式,只有當調用的子函數完全執行完畢纔會結束執行父函數,執行信息保存在一個堆棧當中。 協程其實是突破了堆棧數的限制,主函數一個堆棧,每個異步的回調也有自己的堆棧,當程序執行發生異步的時候,執行權限可以切換給其他函數,因爲堆棧信息一直保留在運行環境中(沒有被切換出去),所以切換成本非常小,一般是直接修改執行函數的引用就可以完成切換。

Nodejs Promise.all執行async函數就是運行一段協程代碼,await關鍵字就是切換協程,在await後就去執行其他協程的代碼了。es6中爲了實現協程,提供了Generator函數和yield關鍵字,但是語法比較繁瑣,後來對其進行了包裝,變成了async函數和await關鍵字

nodejs協程的缺點 線程是基於時間片的,也就是說一個線程卡死,不會影響其他線程的執行,但是nodejs協程不同,一個協程卡死將導致執行權限無法釋放,導致其他的協程也無法執行。

go語言的協程

nodejs因爲是單線程的,協程無法使用多核,也就是說無法真正的併發執行多個函數。 go語言設計了多核版本的協程,也就是說,同一時間多個協程可以被多個CPU真正的併發執行,或者你可以開多個線程,讓多個線程去調度協程序,避免程序假死的問題。因爲go的優秀的協程處理機制,區塊鏈優先採用了go作爲開發語言。

不同於傳統的多進程或多線程,golang的併發執行單元是一種稱爲goroutine的協程。語言級別支持協程(goroutine)併發(協程又稱微線程,比線程更輕量、開銷更小,性能更高),操作起來非常簡單,語言級別提供關鍵字(go)用於啓動協程,並且在同一臺機器上可以啓動成千上萬個協程。協程經常被理解爲輕量級線程,一個線程可以包含多個協程,共享堆不共享棧。協程間一般由應用程序顯式實現調度,上下文切換無需下到內核層,高效不少。協程間一般不做同步通訊,而golang中實現協程間通訊有兩種:1)共享內存型,即使用全局變量+mutex鎖來實現數據共享;2)消息傳遞型,即使用一種獨有的channel機制進行異步通訊。

Python協程 asyncio.create_task() 函數用來併發運行作爲 asyncio 任務 的多個協程。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章