溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Node.js中阻塞與非阻塞的示例分析

發(fā)布時間:2020-12-08 10:33:57 來源:億速云 閱讀:160 作者:小新 欄目:web開發(fā)

小編給大家分享一下Node.js中阻塞與非阻塞的示例分析,希望大家閱讀完這篇文章后大所收獲,下面讓我們一起去探討吧!

阻塞與非阻塞概述

此概述介紹了Node.js中阻塞與非阻塞調(diào)用之間的區(qū)別,此概述將引用事件循環(huán)和libuv,但不需要事先了解這些主題,假設讀者對JavaScript語言和Node.js回調(diào)模式有基本的了解。

“I/O”主要指與libuv支持的系統(tǒng)的磁盤和網(wǎng)絡的交互。

阻塞

阻塞是指在Node.js進程中執(zhí)行其他JavaScript必須等到非JavaScript操作完成,發(fā)生這種情況是因為在發(fā)生阻塞操作時,事件循環(huán)無法繼續(xù)運行JavaScript。

在Node.js中,由于CPU密集而不是等待非JavaScript操作而表現(xiàn)出較差性能的JavaScript,例如I/O,通常不稱為阻塞。Node.js標準庫中使用libuv的同步方法是最常用的阻塞操作,原生模塊也可能具有阻塞方法。

Node.js標準庫中的所有I/O方法都提供非阻塞的異步版本,并接受回調(diào)函數(shù),某些方法還具有對應的阻塞方法,其名稱以Sync結尾。

比較代碼

阻塞方法同步執(zhí)行,非阻塞方法異步執(zhí)行。

以文件系統(tǒng)模塊為例,這是一個同步讀取文件的方法:

const fs = require('fs');
const data = fs.readFileSync('/file.md'); // blocks here until file is read

這是一個等效的異步示例:

const fs = require('fs');
fs.readFile('/file.md', (err, data) => {
  if (err) throw err;
});

第一個示例看起來比第二個示例更簡單,但缺點是第二行阻止執(zhí)行任何其他JavaScript,直到讀取整個文件,請注意,在同步版本中,如果拋出錯誤,則需要捕獲它,否則進程將崩潰,在異步版本中,由作者決定是否應該如圖所示拋出錯誤。

讓我們稍微擴展一下我們的例子:

const fs = require('fs');
const data = fs.readFileSync('/file.md'); // blocks here until file is read
console.log(data);
// moreWork(); will run after console.log

這是一個類似但不等同的異步示例:

const fs = require('fs');
fs.readFile('/file.md', (err, data) => {
  if (err) throw err;
  console.log(data);
});
// moreWork(); will run before console.log

在上面的第一個示例中,將在moreWork()之前調(diào)用console.log,在第二個示例中,fs.readFile()是非阻塞的,因此JavaScript執(zhí)行可以繼續(xù),并且將首先調(diào)用moreWork(),在不等待文件讀取完成的情況下運行moreWork()的能力是一個關鍵的設計選擇,可以提高吞吐量。

并發(fā)和吞吐量

Node.js中的JavaScript執(zhí)行是單線程的,因此并發(fā)性是指事件循環(huán)在完成其他工作后執(zhí)行JavaScript回調(diào)函數(shù)的能力,任何預期以并發(fā)方式運行的代碼都必須允許事件循環(huán)繼續(xù)運行,因為非JavaScript操作(如I/O)正在發(fā)生。

作為一個例子,讓我們考慮這樣一種情況:每個Web服務器請求需要50ms才能完成,50ms中的45ms是可以異步完成的數(shù)據(jù)庫I/O,選擇非阻塞異步操作可以釋放每個請求45毫秒來處理其他請求,僅通過選擇使用非阻塞方法而不是阻塞方法,這是容量的顯著差異。

事件循環(huán)不同于許多其他語言中的模型,其中可以創(chuàng)建其他線程來處理并發(fā)工作。

混合阻塞和非阻塞代碼的危險

處理I/O時應該避免一些模式,我們來看一個例子:

const fs = require('fs');
fs.readFile('/file.md', (err, data) => {
  if (err) throw err;
  console.log(data);
});
fs.unlinkSync('/file.md');

在上面的例子中,fs.unlinkSync()很可能在fs.readFile()之前運行,這會在實際讀取之前刪除file.md,寫一個更好的方法是完全無阻塞并保證以正確的順序執(zhí)行:

const fs = require('fs');
fs.readFile('/file.md', (readFileErr, data) => {
  if (readFileErr) throw readFileErr;
  console.log(data);
  fs.unlink('/file.md', (unlinkErr) => {
    if (unlinkErr) throw unlinkErr;
  });
});

上面在fs.readFile()的回調(diào)中對fs.unlink()進行了非阻塞調(diào)用,這保證了正確的操作順序。

看完了這篇文章,相信你對Node.js中阻塞與非阻塞的示例分析有了一定的了解,想了解更多相關知識,歡迎關注億速云行業(yè)資訊頻道,感謝各位的閱讀!

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權內(nèi)容。

AI