Nodejs編程是全異步的,這就意味著我們不必每次都阻塞等待該次操作的結(jié)果,而事件完成(就緒)時(shí)會(huì)主動(dòng)回調(diào)通知我們。在網(wǎng)絡(luò)編程中,一般都是基于Reactor線(xiàn)程模型的變種,無(wú)論其怎么演化,其核心組件都包含了Reactor實(shí)例(提供事件注冊(cè)、注銷(xiāo)、通知功能)、多路復(fù)用器(由操作系統(tǒng)提供,比如kqueue、select、epoll等)、事件處理器(負(fù)責(zé)事件的處理)以及事件源(linux中這就是描述符)這四個(gè)組件。一般,會(huì)單獨(dú)啟動(dòng)一個(gè)線(xiàn)程運(yùn)行Reactor實(shí)例來(lái)實(shí)現(xiàn)真正的異步操作。但是,依賴(lài)操作系統(tǒng)提供的系統(tǒng)調(diào)用來(lái)實(shí)現(xiàn)異步是有局限的,比如在Reactor模型中我們只能監(jiān)聽(tīng)到:網(wǎng)絡(luò)IO事件、signel(信號(hào))、超時(shí)事件以及一些管道事件等,但這些事件也只是通知我們資源可讀或者可寫(xiě),真正的讀寫(xiě)操作(read和write)還是同步的(也就是你必須等到read或者write返回,雖然linux提供了aio,但是其有諸多槽點(diǎn)),那么Nodejs的全異步是如何做到的呢?你可能會(huì)很快想到,就是啟用單獨(dú)的線(xiàn)程來(lái)做同步的事情,這也是libuv的設(shè)計(jì)思路,借用官網(wǎng)的一張圖,說(shuō)明一切:

      由上圖可以看到,libuv實(shí)現(xiàn)了一套自己的線(xiàn)程池來(lái)處理所有同步操作(從而模擬出異步的效果),下面就來(lái)看一下該線(xiàn)程池的具體實(shí)現(xiàn)吧!

 一、線(xiàn)程池模型

     說(shuō)道線(xiàn)程池,在java領(lǐng)域中,jdk本身就提供了多種線(xiàn)程池實(shí)現(xiàn),幾乎所有的線(xiàn)程池都遵循以下模型(任務(wù)隊(duì)列+線(xiàn)程池):

        

      libuv自身定義了一個(gè)非常精煉、高效的隊(duì)列(雙向循環(huán)鏈表),只用了幾個(gè)簡(jiǎn)單的宏定義將其實(shí)現(xiàn),具體實(shí)現(xiàn)方式可以參見(jiàn)我的另一篇博文:libuv高效隊(duì)列的實(shí)現(xiàn)?,F(xiàn)在隊(duì)列有了,來(lái)看一下task的定義: