iT邦幫忙

2024 iThome 鐵人賽

DAY 10
0
自我挑戰組

30 天 Node.js 探索:基礎、進階與實踐系列 第 10

Day 10: Node.js 單執行緒模型與非阻塞 I/O

  • 分享至 

  • xImage
  •  

接下來要理解 Node.js 單執行緒模型及其非阻塞 I/O 機制,進一步加深對 Node.js 高效處理並發請求的認識。

Node.js 是單執行緒的?

Node.js 採用了 單執行緒模型,所以全部的 JavaScript 代碼都在同一個執行緒中執行。但這個模型並不會限制 Node.js 的並發處理能力,因為它利用了非阻塞 I/O 和事件驅動架構來高效處理多個請求。

  • 單執行緒: 所有的 JavaScript 執行都在同一個執行緒上進行,避免了多執行緒下的競爭條件的問題。
  • 非阻塞 I/O: 雖然代碼在單執行緒上執行,但 I/O 操作(如文件讀寫、網路請求)並不會阻塞這個執行緒。

非阻塞 I/O 概念

Node.js 使用非阻塞 I/O 來實現高效的並發處理。當執行 I/O 操作時(例如讀取文件或處理網絡請求),Node.js 不會等待操作完成,而是繼續處理其他請求。

  • 阻塞 I/O: 在傳統模型中,I/O 操作會阻塞執行緒,直到操作完成。這會導致系統無法同時處理多個請求。
  • 非阻塞 I/O: Node.js 採用非阻塞方式來處理 I/O 操作,當 I/O 完成後會以事件的形式通知應用程式,這樣可以同時處理多個 I/O 任務。

單執行緒如何處理並發?

Node.js 的單執行緒模型與非阻塞 I/O 使其能夠高效處理大量的並發請求。這是透過事件循環回調函數 來完成的。當 I/O 操作完成後,對應的回調函數會被放入事件循環中執行,這樣單一執行緒也能高效管理大量的任務。

CPU 密集型任務的挑戰

雖然非阻塞 I/O 適合處理 I/O 密集型任務,但對於 CPU 密集型任務(如大量數據計算),Node.js 的單執行緒模型可能會帶來性能的瓶頸。這時候可以考慮使用以下的解決方式:

  • 子進程(Child Processes): 將 CPU 密集型任務交給子進程來去處理。
  • 工作者執行緒(Worker Threads): Node.js 內建的多執行緒支持,適合計算密集的任務。

非阻塞文件讀取與阻塞操作的對比

接下來要利用一個範例來表示非阻塞和阻塞操作這兩者的區別。
非阻塞文件讀取的範例:

js
const fs = require('fs');

console.log('Start reading file...');

fs.readFile('example.txt', 'utf8', (err, data) => {
  if (err) throw err;
  console.log('File content:', data);
});

console.log('Continue with other tasks...');

實際打入 Node.js ,執行結果會如下:
https://ithelp.ithome.com.tw/upload/images/20240922/20169444otcPUBoz9v.png
阻塞文件讀取的範例:

js
const fs = require('fs');

console.log('Start reading file...');

const data = fs.readFileSync('example.txt', 'utf8');
console.log('File content:', data);

console.log('Continue with other tasks...');

實際打入 Node.js ,執行結果會如下:
https://ithelp.ithome.com.tw/upload/images/20240922/20169444DC3g90YucS.png
在非阻塞版本中,文件讀取操作不會阻塞主執行緒,程序會繼續執行其他代碼。而在阻塞版本中,程序必須等到文件讀取完成後才繼續執行後面的代碼。

單執行緒與多執行緒的對比

Node.js 的單執行緒模型相比傳統的多執行緒模型有一些優點和挑戰:
** 優點** :

  • 不需要處理複雜的執行緒同步問題(像是Deadlock)。
  • 使用事件驅動和非阻塞 I/O,能夠高效地處理 I/O 密集型任務。
    ** 挑戰** :
  • 若處理更高難度的 CPU 密集型任務可能會有性能瓶頸。
  • 需要合理設計程序以避免阻塞事件循環。

總結

今天我們深入探討了 Node.js 的單執行緒模型與非阻塞 I/O 機制,了解了它如何在單一執行緒上高效地處理多個並發請求而不被阻塞。這些概念剛好應證了 Node.js 在處理 I/O 密集型任務時的高效性與靈活性,而且還能夠承受高並發的應用程式。在後續的實作中,將運用這些理論知識,設計出更具可擴展性和效能的應用。


上一篇
Day 9: Middleware 中介軟體的概念與使用
下一篇
Day 11:REST API 基礎與 Express 結合
系列文
30 天 Node.js 探索:基礎、進階與實踐30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言