node.js 底層使用的是epoll這種單線程io多路復用,還是多線程阻塞模型?

朴靈老師在 深入淺出Node.js(五):初探Node.js的非同步I/O實現 一文中寫道:

所幸的是,libev的作者Marc Alexander Lehmann重新實現了一個非同步I/O的庫:libeio。libeio實質依然是採用線程池與阻塞I/O模擬出來的非同步I/O。

而這和知乎中的幾個回答似乎不太一致:

node.js在linux上面操作非同步IO的時候,為什麼沒有直接用epoll? - 藍形參的回答epoll 或者

kqueue 的原理是什麼? - 藍形參的回答

Linux IO 多路復用是什麼意思,一直沒弄明白? - 羅志宇的回答

I/O multiplexing 這裡面的 multiplexing 指的其實是在單個線程通過記錄跟蹤每一個Sock(I/O流)的狀態(對應空管塔裡面的Fight progress strip槽)來同時管理多個I/O流

select, poll, epoll 都是I/O多路復用的具體的實現

只不過使用libuv封裝了epoll。


io分為網路IO和磁碟IO,對於網路IO,使用epoll之類的就可以了。但是對於瓷盤IO,沒有完美的辦法,所以都是使用多線程阻塞模擬的,不同在於Windows下的IOCP是在系統內核里提供的線程池,而Linux之類的在用戶層提供的線程池。

libeio和libev是node較早版本使用的,在libuv提供之後,這兩個庫均不在使用。


至少Linux和BSD上,磁碟IO是用線程池模擬的,網路IO是epoll/kqueue進行多路復用。

Windows上的實現不清楚,有可能磁碟IO和網路IO都是真正的非同步。


首先,腦海中有個矩陣:

********阻塞 | 非阻塞

同步 | read | x

非同步 | select/poll/epoll | AIO

一共有4種IO模式。read 和 epoll等阻塞的內容不一樣,前者阻塞在整個IO調用上,後者阻塞在等待IO事件通知(多路復用就是多個文件句柄的多個狀態變更通知)。

本來最爽的是非同步非阻塞AIO,給一個buffer和回調函數,調用aio_read,數據好了,系統自動填充buffer(即:數據從內核拷到用戶空間;write反過來),然後調用你的函數;但函數在內核棧執行,這樣就變成雞肋了,很少人用的。

nodejs以及java的nio等,都是非同步阻塞IO。select poll epoll不管是單路還是多路,都需要有個線程在那阻塞等事件通知,通知有數據了,就調用你的回調函數; 對用戶程序來說,就是一個模擬的AIO。


因為你看的博客過時了, 那是12年寫的. 那時候libuv還在用libev libeio, 然而它們至少在13年就被libuv棄用了, 詳細的你可以查.


推薦閱讀:

TAG:Linux | Nodejs | epoll | 多線程 |