日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
讓Node.js變“懶”的COW技術(shù)

COW 不是奶牛,是 Copy-On-Write 的縮寫,這是一種是復(fù)制但也不完全是復(fù)制的技術(shù)。

一般來說復(fù)制就是創(chuàng)建出完全相同的兩份,兩份是獨(dú)立的:

但是,有的時(shí)候復(fù)制這件事沒多大必要,完全可以復(fù)用之前的,這時(shí)候可以只是引用之前的那份,在寫內(nèi)容的時(shí)候才去復(fù)制對(duì)應(yīng)的一部分內(nèi)容。這樣如果內(nèi)容用于讀的話,就免去了復(fù)制,而如果需要寫,才會(huì)真正復(fù)制部分內(nèi)容來做修改。

這就叫做“寫時(shí)復(fù)制”,也就是 Copy-On-Write。

原理很簡(jiǎn)單,但是在操作系統(tǒng)的內(nèi)存管理和文件系統(tǒng)中卻很常見,Node.js 里面也因?yàn)檫@種技術(shù)變“懶”了。

本文我們來探究下 Copy-On-Write 在 Node.js 的進(jìn)程創(chuàng)建和文件復(fù)制的應(yīng)用:

文件復(fù)制

文件復(fù)制這件事最常見的思路就是完全寫一份相同的文件內(nèi)容到另一個(gè)位置,但是這樣有兩個(gè)問題:

  • 完全寫一份相同的內(nèi)容,如果同樣的文件復(fù)制了幾百次,那么也創(chuàng)建相同的內(nèi)容幾百次么?太浪費(fèi)硬盤空間了
  • 如果寫到一半斷電了怎么辦?覆蓋的內(nèi)容如何恢復(fù)?

怎么辦呢?這時(shí)候操作系統(tǒng)設(shè)計(jì)者就想到了 COW 技術(shù)。

用 COW 技術(shù)實(shí)現(xiàn)文件復(fù)制以后完美解決了上面兩個(gè)問題:

  • 復(fù)制只是添加一個(gè)引用到之前的內(nèi)容,如果不修改并不會(huì)真正復(fù)制,只有到第一次修改內(nèi)容的時(shí)候才去真正復(fù)制對(duì)應(yīng)的數(shù)據(jù)塊,這樣就避免了大量硬盤空間的浪費(fèi)。
  • 寫文件時(shí)會(huì)先在另一個(gè)空閑磁盤塊做修改,等修改完之后才會(huì)復(fù)制到目標(biāo)位置,這樣就不會(huì)有斷電無法回滾的問題

在 Node.js 的 fs.copyFile 的 api 就可以使用 Copy-On-Write 模式:

默認(rèn)情況下,copyFile 會(huì)寫入目標(biāo)文件,覆蓋原內(nèi)容

 
 
 
 
  1. const fsPromises = require('fs').promises;
  2. (async function() {
  3.   try {
  4.     await fsPromises.copyFile('source.txt', 'destination.txt');
  5.   } catch(e) {
  6.     console.log(e.message);
  7.   }
  8. })();

但是可以通過第三個(gè)參數(shù)指定復(fù)制的策略:

 
 
 
 
  1. const fs = require('fs');
  2. const fsPromises = fs.promises;
  3. const { COPYFILE_EXCL, COPYFILE_FICLONE, COPYFILE_FICLONE_FORCE} = fs.constants;
  4. (async function() {
  5.   try {
  6.     await fsPromises.copyFile('source.txt', 'destination.txt', COPYFILE_FICLONE);
  7.   } catch(e) {
  8.     console.log(e.message);
  9.   }
  10. })();

支持的 flag 有 3 個(gè):

  • COPYFILE_EXCL: 如果目標(biāo)文件已存在,會(huì)報(bào)錯(cuò)(默認(rèn)是覆蓋)
  • COPYFILE_FICLONE: 以 copy-on-write 模式復(fù)制,如果操作系統(tǒng)不支持就轉(zhuǎn)為真正的復(fù)制(默認(rèn)是直接復(fù)制)
  • COPYFILE_FICLONE_FORCE:以 copy-on-write 模式復(fù)制,如果操作系統(tǒng)不支持就報(bào)錯(cuò)

這3個(gè)常量分別是 1,2,4,可以通過按位或把它們合并之后傳入:

 
 
 
 
  1. const flags = COPYFILE_FICLONE | COPYFILE_EXCL;
  2. fsPromises.copyFile('source.txt', 'destination.txt', flags);

Node.js 支持操作系統(tǒng)的 copy-on-write 技術(shù),在一些場(chǎng)景下可以提升性能,建議使用 COPYFILE_FICLONE 的方式,會(huì)比默認(rèn)的方式好一些。

進(jìn)程創(chuàng)建

fork 是常見的創(chuàng)建進(jìn)程的方式,而它的實(shí)現(xiàn)就是一種 copy-on-write 技術(shù)。

我們知道,進(jìn)程在內(nèi)存中分為代碼段、數(shù)據(jù)段、堆棧段這 3 部分:

  • 代碼段:存放要執(zhí)行的代碼
  • 數(shù)據(jù)段:存放一些全局?jǐn)?shù)據(jù)
  • 堆棧段:存放執(zhí)行的狀態(tài)

如果基于該進(jìn)程創(chuàng)建一個(gè)新的進(jìn)程,那么要復(fù)制這 3 部分內(nèi)存。而如果這三部分內(nèi)存是一樣的內(nèi)容,那就浪費(fèi)了內(nèi)存空間。

所以 fork 并不會(huì)真正的復(fù)制內(nèi)存,而是創(chuàng)建一個(gè)新的進(jìn)程,引用父進(jìn)程的內(nèi)存,當(dāng)做數(shù)據(jù)的修改的時(shí)候,才會(huì)真正復(fù)制該部分的內(nèi)存。

這也是為什么把進(jìn)程創(chuàng)建叫做 fork,也就是分叉,因?yàn)椴煌耆仟?dú)立的,只是某部分做了分叉,成了兩份,但是大部分還是一樣的。

但如果要執(zhí)行的代碼不一樣怎么辦呢,這時(shí)候就要用 exec 了,它會(huì)創(chuàng)建新的代碼段、數(shù)據(jù)段、堆棧段、執(zhí)行新的代碼。

Node.js 里面同樣可以用 fork 和 exec 的 api:

fork:

 
 
 
 
  1. const cluster = require('cluster');
  2. if (cluster.isMaster) {
  3.   console.log('I am master');
  4.   cluster.fork();
  5.   cluster.fork();
  6. } else if (cluster.isWorker) {
  7.   console.log(`I am worker #${cluster.worker.id}`);
  8. }

exec:

 
 
 
 
  1. const { exec } = require('child_process');
  2. exec('my.bat', (err, stdout, stderr) => {
  3.   if (err) {
  4.     console.error(err);
  5.     return;
  6.   }
  7.   console.log(stdout);
  8. });

fork 是 linux 進(jìn)程創(chuàng)建的基礎(chǔ),由此可見 copy-on-write 技術(shù)多么重要了。

總結(jié)

復(fù)制同樣的內(nèi)容多份無疑比較浪費(fèi)空間,所以操作系統(tǒng)在做文件復(fù)制、進(jìn)程創(chuàng)建時(shí)的內(nèi)存復(fù)制的時(shí)候都采用了 Copy-On-Write 技術(shù),只有真正修改的時(shí)候才會(huì)去做復(fù)制。

Node.js 支持了 fs.copyFile 的 flags 的設(shè)置,可以指定 COPYFILE_FICLONE 來使用 Copy-On-Write 的方式做文件復(fù)制,也建議大家使用這種方式來節(jié)省硬盤空間,提高文件復(fù)制的性能。

進(jìn)程的 fork 也是 Copy-On-Write 的實(shí)現(xiàn),并不會(huì)直接復(fù)制進(jìn)程的代碼段、數(shù)據(jù)段、堆棧段到新的內(nèi)容,而是引用之前的,只有在修改的時(shí)候才會(huì)做真正的內(nèi)存復(fù)制。

除此以外,Copy-On-Write 在 Immutable 的實(shí)現(xiàn),在分布式的讀寫分離等領(lǐng)域都有很多應(yīng)用。

COW 讓 Node.js 變“懶”了,但性能卻更高了。


分享名稱:讓Node.js變“懶”的COW技術(shù)
文章鏈接:http://www.5511xx.com/article/dhhiesp.html