node讀取文件功能的代碼跟蹤調(diào)查

當我們快樂的使用js寫服務端程序的時候,是否想過如此酸爽的編程體驗是如何實現(xiàn)的。為了滿足自己的好奇心,我特意下載了node的源碼座掘,進行了一次深度跟蹤。

我們看一下readFile這個程序到底是如何實現(xiàn)的吧柔滔。由于v8很復雜溢陪,所以這篇文章中v8如何幫助我們在js和cpp來回調(diào)用就忽略了,等我把v8也研究了再來補上睛廊。js形真,node,和libuv的代碼超全,會比較詳細的跟蹤咆霜。

跟蹤方法

  • 新建測試文件
    新建一個文件:fsdemo.js, 用這個文件來調(diào)試吧。
var fs = require("fs");

// 異步讀取
fs.readFile('vcbuild.bat', function(err, data) {
    if (err) {
        return console.error("Yin : in the fsdemo.js :: 異步讀取發(fā)生錯誤 : " + err);
    }
    console.log("Yin : in the fsdemo.js :: 異步讀取完畢 嘶朱!\n");

    // console.log("異步讀取: " + data.toString());
});

// 同步讀取
// var data = fs.readFileSync('input.txt');
// console.log("同步讀取: " + data.toString());

console.log("Yin : in the fsdemo.js :: 程序執(zhí)行完畢蛾坯。\n");
  • 下載node
    https://github.com/nodejs/node
    切換到4.4.7版本。最新的跟不上疏遏,太老的bug多脉课,我們跟蹤一個LTSb按本吧救军。
    我是在windows上用visual studio看代碼,所以直接運行vcbuild倘零。
    確保按照readme的說明編譯成功哦唱遭。

  • 打上log
    先過一遍代碼后,可以在感興趣的地方打上log呈驶。如果希望用斷點調(diào)試拷泽,也可以直接在VS中F11,找到入口袖瞻。后面會貼上我增加的log跌穗,感興趣的同學可以自己對照著改改。

  • 反復調(diào)試
    一次找到所有的路徑是很困難的虏辫,因為異步的代碼會跳來跳去,所以需要仔細思考锈拨,才能找到整條路徑砌庄。


Log講解

在調(diào)試了以4,5個小時后,感覺已經(jīng)摸清了異步調(diào)用的基本流程奕枢。感興趣的朋友可以仔細看看娄昆。下面的log需要你對代碼頁非常熟悉。


** 1. 加載需要測試的文件 **

Yin : in the node_file.cc! :: Open
Yin : in the node_file.cc! :: Open :: SYNC_CALL! path = \?\D:\projects\node\fsdemo.js
Yin : in the fs.c :: uv_fs_open!
Yin : in the fs.c :: uv_fs_open :: fs__open(req);!
Yin : in the fs.c :: fs__open
Yin : in the node_file.cc! :: Read
Yin : in the node_file.cc! :: Read :: SYNC_CALL, <fd = 3>
Yin : in the fs.c :: uv_fs_read!
Yin : in the fs.c :: uv_fs_read :: fs__read(req); <fd = 3>!
Yin : in the fs.c :: fs__read
Yin : in the fs.c :: fs__read :: ReadFile <index = 0>

上面的log向我們展示了node本身加載fsdemo.js的過程缝彬。通過log可以看到這個過程是同步的萌焰,最后通過libuv的fs__read完成讀取工作。


** 2. js讀取文件**

Yin : in the fs.js :: fs.readFile!
Yin : in the node_file.cc! :: Open
Yin : in the node_file.cc! :: Open :: ASYNC_CALL! path = \?\D:\projects\node\vcbuild.bat
Yin : in the fs.c :: uv_fs_open!
Yin : in the fs.c ::** uv_fs_open :: QUEUE_FS_TP_JOB**!
Yin : in the threadpool.c :: worker
Yin : in the fs.c :: uv__fs_work :: <fstype = open>
Yin : in the fs.c :: fs__open
Yin : in the threadpool.c :: worker :: uv_async_send <&w->loop->wq_async = 23934432>
Yin : in the fsdemo.js :: 程序執(zhí)行完畢谷浅。

通過上面的log扒俯,我們可以知道讀取文件用的是異步方式,任務被放到隊列中一疯,由線程池去執(zhí)行具體的任務撼玄,現(xiàn)在可以看到第一個任務是open,調(diào)用fs__open墩邀。open完成后掌猛,還會通知主線程(uv_async_send)。還可以注意到 fsdemo.js這時候已經(jīng)執(zhí)行完畢了眉睹。


3. open文件的過程

Yin : in core.c :: uv_run
Yin : in the req-inl.h :: uv_process_reqs
Yin : in the node.cc :: StartNodeInstance :: <loop number = 1, more event = 1>
Yin : in core.c :: uv_run
Yin : in the req-inl.h :: uv_process_reqs
Yin : in the req-inl.h :: uv_process_reqs : UV_WAKEUP
Yin : in the threadpool.c :: uv__work_done
Yin : in the threadpool.c :: uv__work_done :: w->done(w, err)
Yin : in the fs.c :: uv__fs_done
Yin : in the node_file.cc! :: After
Yin : in the node_file.cc! :: After :: MakeCallback :: <argc = 2, argv =h???燙燙?>
Yin : in the fs.js :: readFileAfterOpen !

我們可以看到主線程會有一個循環(huán)處理事件±蟛纾現(xiàn)在有一個UV_WAKEUP事件要處理。事件處理完成后會再回調(diào)fs.js里面的readFileAfterOpen函數(shù)竹海。

需要說明的是這里面忽略了另一個線程如何通知主循環(huán)的細節(jié)慕蔚,window平臺是通過IOCP,可以搜索函數(shù)GetQueuedCompletionStatus了解細節(jié)站削,liunx上并不是這樣坊萝。


4. check文件狀態(tài)

Yin : in the threadpool.c :: worker
Yin : in the node.cc :: StartNodeInstance :: <loop number = 2, more event = 1>
Yin : in core.c :: uv_run
Yin : in the req-inl.h :: uv_process_reqs
Yin : in the fs.c :: uv__fs_work :: <fstype = fstat>
Yin : in the threadpool.c :: worker :: uv_async_send <&w->loop->wq_async = 23934432>
Yin : in the node.cc :: StartNodeInstance :: <loop number = 3, more event = 1>
Yin : in core.c :: uv_run
Yin : in the req-inl.h :: uv_process_reqs
Yin : in the req-inl.h :: uv_process_reqs : UV_WAKEUP
Yin : in the threadpool.c :: uv__work_done
Yin : in the threadpool.c :: uv__work_done :: w->done(w, err)
Yin : in the fs.c :: uv__fs_done
Yin : in the node_file.cc! :: After
Yin : in the node_file.cc! :: After :: MakeCallback :: <argc = 2, argv =h???燙燙?>
Yin : in the fs.js :: readFileAfterStat !

這里通過log發(fā)現(xiàn)讀取之前還檢查了一下文件狀態(tài)孵稽,前面都open到fd了,還check啥狀態(tài)十偶,我覺得這里可以優(yōu)化菩鲜,這個就不仔細深究了。


5. 讀文件
Yin : in the fs.js :: ReadFileContext.prototype.read !
Yin : in the node_file.cc! :: Read
Yin : in the node_file.cc! :: Read :: ASYNC_CALL, <fd = 3>
Yin : in the fs.c :: uv_fs_read!
Yin : in the fs.c :: uv_fs_read :: QUEUE_FS_TP_JOB <fd = 3>!
Yin : in the threadpool.c :: worker
Yin : in the node.cc :: StartNodeInstance :: <loop number = 4, more event = 1>
Yin : in the fs.c :: uv__fs_work :: <fstype = read>
Yin : in core.c :: uv_run
Yin : in the fs.c :: fs__read
Yin : in the req-inl.h :: uv_process_reqs
Yin : in the fs.c :: fs__read :: ReadFile <index = 0>
Yin : in the threadpool.c :: worker :: uv_async_send <&w->loop->wq_async = 23934432>
Yin : in the node.cc :: StartNodeInstance :: <loop number = 5, more event = 1>
Yin : in core.c :: uv_run
Yin : in the req-inl.h :: uv_process_reqs
Yin : in the req-inl.h :: uv_process_reqs : UV_WAKEUP
Yin : in the threadpool.c :: uv__work_done
Yin : in the threadpool.c :: uv__work_done :: w->done(w, err)
Yin : in the fs.c :: uv__fs_done

讀文件也是異步的惦积,和打開文件很像


6.關閉文件并調(diào)用js回調(diào)
Yin : in the node_file.cc! :: After
Yin : in the node_file.cc! :: After :: MakeCallback :: <argc = 2, argv =h???燙燙?>
Yin : in the fs.js :: ReadFileContext.prototype.close !
Yin : in the threadpool.c :: worker
Yin : in the node.cc :: StartNodeInstance :: <loop number = 6, more event = 1>
Yin : in core.c :: uv_run
Yin : in the req-inl.h :: uv_process_reqs
Yin : in the fs.c :: uv__fs_work :: <fstype = close>
Yin : in the threadpool.c :: worker :: uv_async_send <&w->loop->wq_async = 23934432>
Yin : in the node.cc :: StartNodeInstance :: <loop number = 7, more event = 1>
Yin : in core.c :: uv_run
Yin : in the req-inl.h :: uv_process_reqs
Yin : in the req-inl.h :: uv_process_reqs : UV_WAKEUP
Yin : in the threadpool.c :: uv__work_done
Yin : in the threadpool.c :: uv__work_done :: w->done(w, err)
Yin : in the fs.c :: uv__fs_done
Yin : in the node_file.cc! :: After
Yin : in the node_file.cc! :: After :: MakeCallback :: <argc = 1, argv =h?>
Yin : in the fs.js :: readFileAfterClose !
Yin : in the fsdemo.js :: 異步讀取完畢 接校!
Yin : in the node.cc :: StartNodeInstance :: <loop number = 8, more event = 0>

可以看到最后回到了js文件。

結(jié)論

可以看到狮崩,用js幾行代碼完成的事情蛛勉,實際上流程非常復雜,上面的代碼還不包括v8如何解析js的情況睦柴,如果能把這些都搞清楚了诽凌,才是大牛吧。

對代碼的修改可以看這個diff文件坦敌。
https://github.com/benhaben/blog/issues/15

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末侣诵,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子狱窘,更是在濱河造成了極大的恐慌杜顺,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,542評論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件蘸炸,死亡現(xiàn)場離奇詭異躬络,居然都是意外死亡,警方通過查閱死者的電腦和手機搭儒,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,822評論 3 394
  • 文/潘曉璐 我一進店門穷当,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人淹禾,你說我怎么就攤上這事膘滨。” “怎么了稀拐?”我有些...
    開封第一講書人閱讀 163,912評論 0 354
  • 文/不壞的土叔 我叫張陵火邓,是天一觀的道長。 經(jīng)常有香客問我德撬,道長铲咨,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,449評論 1 293
  • 正文 為了忘掉前任蜓洪,我火速辦了婚禮纤勒,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘隆檀。我一直安慰自己摇天,他們只是感情好粹湃,可當我...
    茶點故事閱讀 67,500評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著泉坐,像睡著了一般为鳄。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上腕让,一...
    開封第一講書人閱讀 51,370評論 1 302
  • 那天孤钦,我揣著相機與錄音,去河邊找鬼纯丸。 笑死偏形,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的觉鼻。 我是一名探鬼主播俊扭,決...
    沈念sama閱讀 40,193評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼坠陈!你這毒婦竟也來了统扳?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,074評論 0 276
  • 序言:老撾萬榮一對情侶失蹤畅姊,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后吹由,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體若未,經(jīng)...
    沈念sama閱讀 45,505評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,722評論 3 335
  • 正文 我和宋清朗相戀三年倾鲫,在試婚紗的時候發(fā)現(xiàn)自己被綠了粗合。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,841評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡乌昔,死狀恐怖隙疚,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情供屉,我是刑警寧澤,帶...
    沈念sama閱讀 35,569評論 5 345
  • 正文 年R本政府宣布溺蕉,位于F島的核電站,受9級特大地震影響疯特,放射性物質(zhì)發(fā)生泄漏哗魂。R本人自食惡果不足惜漓雅,卻給世界環(huán)境...
    茶點故事閱讀 41,168評論 3 328
  • 文/蒙蒙 一朽色、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧组题,春花似錦葫男、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,783評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至峻呕,卻和暖如春利职,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背瘦癌。 一陣腳步聲響...
    開封第一講書人閱讀 32,918評論 1 269
  • 我被黑心中介騙來泰國打工猪贪, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人讯私。 一個月前我還...
    沈念sama閱讀 47,962評論 2 370
  • 正文 我出身青樓热押,卻偏偏與公主長得像,于是被迫代替她去往敵國和親斤寇。 傳聞我的和親對象是個殘疾皇子桶癣,可洞房花燭夜當晚...
    茶點故事閱讀 44,781評論 2 354

推薦閱讀更多精彩內(nèi)容

  • 前言從Node.js進入人們的視野時,我們所知道的它就由這些關鍵字組成 事件驅(qū)動娘锁、非阻塞I/O牙寞、高效、輕量莫秆,它在官...
    Www劉閱讀 1,542評論 0 18
  • 不知不覺镊屎,已經(jīng)與兒時的那些小伙伴離別多年惹挟。小學畢業(yè),便各奔東西缝驳。偶爾節(jié)假日回家连锯,才能聚在一起,話話往事用狱。她們有的上...
    西青閱讀 430評論 3 2
  • 宣紙上未風干的畫飄來墨香 我站在畫旁 懷念你寫的情書一行一行 看不到我眼里的憂傷 你不必勉強 我只是遺失在沒有你的...
    依依惜若閱讀 236評論 12 6