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