Nodejs的運行原理-科普篇


 

前言

Nodejs目前處境稍顯尷尬很多語言都已經擁有異步非阻塞的能力阿里的思路是比較合適的但是必須要注意絕對不能讓node做太多的業務邏輯他只適合接收生成好的數據然后或渲染后或直接發送到客戶端

為什么nodejs 還可以成為主流技術哪

是因為nodejs 對於大前端來說還是非常重要的技術!!!如果你理解nodejs 的編程原理很容易就會理解angularjsreactjs vuejs 的設計原理

 

NodeJS

Node是一個服務器端JavaScript解釋器用於方便地搭建響應速度快易於擴展的網絡應用。Node使用事件驅動非阻塞I/O 模型而得以輕量和高效非常適合在分布式設備上運行數據密集型的實時應用
Node是一個可以讓JavaScript運行在瀏覽器之外的平台它實現了諸如文件系統模塊操作系統 API、網絡通信等Core JavaScript沒有或者不完善的功能歷史上將JavaScript移植到瀏覽器外的計划不止一個Node.js 是最出色的一個

 

V8引擎

V8 JavaScript引擎是Google用於其Chrome瀏覽器的底層JavaScript引擎很少有人考慮JavaScript在客戶機上實際做了些什么!

實際上,JavaScript引擎負責解釋並執行代碼。Google使用V8創建了一個用C++編寫的超快解釋器該解釋器擁有另一個獨特特征您可以下載該引擎並將其嵌入任何應用程序。V8 JavaScript引擎並不僅限於在一個瀏覽器中運行

因此,Node實際上會使用Google編寫的V8 JavaScript引擎並將其重建為可在服務器上使用

 

事件驅動

在我們使用Java,PHP等語言實現編程的時候我們面向對象編程是完美的編程設計這使得他們對其他編程方法不屑一顧卻不知大名鼎鼎Node使用的卻是事件驅動編程的思想那什么是事件驅動編程
事件驅動編程為需要處理的事件編寫相應的事件處理程序代碼在事件發生時執行 
為需要處理的事件編寫相應的事件處理程序要理解事件驅動和程序就需要與非事件驅動的程序進行比較實際上現代的程序大多是事件驅動的比如多線程的程序肯定是事件驅動的早期則存在許多非事件驅動的程序這樣的程序在需要等待某個條件觸發時會不斷地檢查這個條件直到條件滿足這是很浪費cpu時間的而事件驅動的程序則有機會釋放cpu從而進入睡眠態注意是有機會當然程序也可自行決定不釋放cpu),當事件觸發時被操作系統喚醒這樣就能更加有效地使用cpu。
來看一張簡單的事件驅動模型(uml):

 

事件驅動模型主要包含3個對象事件源事件和事件處理程序

  事件源產生事件的地方(html元素)

  事件點擊/鼠標操作/鍵盤操作等等

  事件對象當某個事件發生時可能會產生一個事件對象該時間對象會封裝好該時間的信息傳遞給事件處理程序

  事件處理程序響應用戶事件的代碼 

 

運行原理

當我們搜索Node.js奪眶而出的關鍵字就是 “單線程異步I/O,事件驅動”,應用程序的請求過程可以分為倆個部分:CPU運算和I/O讀寫,CPU計算速度通常遠高於磁盤讀寫速度這就導致CPU運算已經完成但是不得不等待磁盤I/O任務完成之后再繼續接下來的業務
所以I/O才是應用程序的瓶頸所在I/O密集型業務中假設請求需要100ms來完成其中99ms化在I/O如果需要優化應用程序讓他能同時處理更多的請求我們會采用多線程同時開啟100、1000個線程來提高我們請求處理當然這也是一種可觀的方案
但是由於一個CPU核心在一個時刻只能做一件事情操作系統只能通過將CPU切分為時間片的方法讓線程可以較為均勻的使用CPU資源但操作系統在內核切換線程的同時也要切換線程的上線文當線程數量過多時時間將會被消耗在上下文切換中所以在大並發時多線程結構還是無法做到強大的伸縮性
那么是否可以另辟蹊徑呢?!我們先來看看單線程,《深入淺出Node》一書提到 “單線程的最大好處是不用像多線程編程那樣處處在意狀態的同步問題這里沒有死鎖的存在也沒有線程上下文切換所帶來的性能上的開銷”,那么一個線程一次只能處理一個請求豈不是無稽之談先讓我們看張圖

Node.js的單線程並不是真正的單線程只是開啟了單個線程進行業務處理(cpu的運算),同時開啟了其他線程專門處理I/O。當一個指令到達主線程主線程發現有I/O之后直接把這個事件傳給I/O線程不會等待I/O結束后再去處理下面的業務而是拿到一個狀態后立即往下走這就是單線程”、“異步I/O”。
I/O操作完之后呢?Node.jsI/O 處理完之后會有一個回調事件這個事件會放在一個事件處理隊列里頭在進程啟動時node會創建一個類似於While(true)的循環它的每一次輪詢都會去查看是否有事件需要處理是否有事件關聯的回調函數需要處理如果有就處理然后加入下一個輪詢如果沒有就退出進程這就是所謂的事件驅動”。這也從Node的角度解釋了什么是事件驅動”。
node.js事件主要來源於網絡請求文件I/O根據事件的不同對觀察者進行了分類有文件I/O觀察者網絡I/O觀察者事件驅動是一個典型的生產者/消費者模型請求到達觀察者那里事件循環從觀察者進行消費主線程就可以馬不停蹄的只關注業務不用再去進行I/O等待

 

優點

Node 公開宣稱的目標是 “旨在提供一種簡單的構建可伸縮網絡程序的方法”。我們來看一個簡單的例子 Java PHP 這類語言中每個連接都會生成一個新線程每個新線程可能需要 2 MB 的配套內存在一個擁有 8 GB RAM 的系統上理論上最大的並發連接數量是 4,000 個用戶隨着您的客戶群的增長如果希望您的 Web 應用程序支持更多用戶那么您必須添加更多服務器所以在傳統的后台開發中整個 Web 應用程序架構包括流量處理器速度和內存速度中的瓶頸是服務器能夠處理的並發連接的最大數量這個不同的架構承載的並發數量是不一致的
Node的出現就是為了解決這個問題更改連接到服務器的方式Node 聲稱它不允許使用鎖它不會直接阻塞 I/O 調用。Node在每個連接發射一個在 Node 引擎的進程中運行的事件而不是為每個連接生成一個新的 OS 線程並為其分配一些配套內存)。

 

缺點

如上所述,nodejs的機制是單線程這個線程里面有一個事件循環機制處理所有的請求在事件處理過程中它會智能地將一些涉及到IO、網絡通信等耗時比較長的操作交由worker threads去執行執行完了再回調這就是所謂的異步IO非阻塞吧但是那些非IO操作只用CPU計算的操作它就自己扛了比如算什么斐波那契數列之類它是單線程這些自己扛的任務要一個接着一個地完成前面那個沒完成后面的只能干等因此CPU要求比較高的CPU密集型任務多的話就有可能會造成號稱高性能適合高並發的node.js服務器反應緩慢

 

適合場景

1、RESTful API

這是適合 Node 的理想情況,因為您可以構建它來處理數萬條連接。它仍然不需要大量邏輯;它本質上只是從某個數據庫中查找一些值並將它們組成一個響應。由於響應是少量文本,入站請求也是少量的文本,因此流量不高,一台機器甚至也可以處理最繁忙的公司的 API 需求。

2、實時程序

比如聊天服務

聊天應用程序是最能體現 Node.js 優點的例子:輕量級、高流量並且能良好的應對跨平台設備上運行密集型數據(雖然計算能力低)。同時,聊天也是一個非常值得學習的用例,因為它很簡單,並且涵蓋了目前為止一個典型的 Node.js 會用到的大部分解決方案。

3、單頁APP

ajax很多。現在單頁的機制似乎很流行,比如phonegap做出來的APP,一個頁面包打天下的例子比比皆是。

總而言之,NodeJS適合運用在高並發、I/O密集、少量業務邏輯的場景

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM