Nodejs編程是全異步的,這就意味著我們不必每次都阻塞等待該次操作的結(jié)果,而事件完成(就緒)時(shí)會(huì)主動(dòng)回調(diào)通知我們。在網(wǎng)絡(luò)編程中,一般都是基于Reactor線程模型的變種,無論其怎么演化,其核心組件都包含了Reactor實(shí)例(提供事件注冊(cè)、注銷、通知功能)、多路復(fù)用器(由操作系統(tǒng)提供,比如kqueue、select、epoll等)、事件處理器(負(fù)責(zé)事件的處理)以及事件源(linux中這就是描述符)這四個(gè)組件。一般,會(huì)單獨(dú)啟動(dòng)一個(gè)線程運(yùn)行Reactor實(shí)例來實(shí)現(xiàn)真正的異步操作。但是,依賴操作系統(tǒng)提供的系統(tǒng)調(diào)用來實(shí)現(xiàn)異步是有局限的,比如在Reactor模型中我們只能監(jiān)聽到:網(wǎng)絡(luò)IO事件、signel(信號(hào))、超時(shí)事件以及一些管道事件等,但這些事件也只是通知我們資源可讀或者可寫,真正的讀寫操作(read和write)還是同步的(也就是你必須等到read或者write返回,雖然linux提供了aio,但是其有諸多槽點(diǎn)),那么Nodejs的全異步是如何做到的呢?你可能會(huì)很快想到,就是啟用單獨(dú)的線程來做同步的事情,這也是libuv的設(shè)計(jì)思路,借用官網(wǎng)的一張圖,說明一切:
由上圖可以看到,libuv實(shí)現(xiàn)了一套自己的線程池來處理所有同步操作(從而模擬出異步的效果),下面就來看一下該線程池的具體實(shí)現(xiàn)吧!
一、線程池模型
說道線程池,在java領(lǐng)域中,jdk本身就提供了多種線程池實(shí)現(xiàn),幾乎所有的線程池都遵循以下模型(任務(wù)隊(duì)列+線程池):
libuv自身定義了一個(gè)非常精煉、高效的隊(duì)列(雙向循環(huán)鏈表),只用了幾個(gè)簡(jiǎn)單的宏定義將其實(shí)現(xiàn),具體實(shí)現(xiàn)方式可以參見我的另一篇博文:libuv高效隊(duì)列的實(shí)現(xiàn)?,F(xiàn)在隊(duì)列有了,來看一下task的定義:
1 struct uv__work { 2 void (*work)(