如何評價fibjs?


1, 用 fiber 還是等語法層面的改進,我認為是見仁見智。我不認為讓開發者關心一個調用是同步還是非同步是一件好事情。

我在微博上面說過,非同步是會向上傳染的,語言級的協程無法根本解決非同步問題。在一個層級較深的項目裡面,一旦底層中有一個模塊需要同步改非同步或者相反(比如需要增加一次資料庫操作),向上的每一個層級都需要在語法上進行修改,這一點是災難的。我不認為 js 能最終解決這個問題,最後必須回歸堆棧級協程。

2, 從純 js 性能來說,fiber 比 callback 要高出非常多。fibjs 的模塊之間是最簡單的函數調用關係,而 callback 則需要往返兩次才能完成一次調用,期間還要結果組包,錯誤處理,保存工作狀態等等耗時操作。同時 nodejs 的事件隊列也是一個性能堪憂的東西。越複雜的應用,這些影響越大。

資料庫操作,沒有做詳細對比測試。封裝 leveldb 的時候簡單測試了一下,fibjs 9w/s,nodejs 3w/s。http + mongodb 有網友測試結果在這裡:http://baoz.cn/499353,基本也是將近 3 倍。並且這些測試裡面,fibjs 的瓶頸根本不在 fibjs 而 nodejs 則是已經跑滿了。

3, 一說生態我就沒話說了哈哈。

下面是關於 fibjs 的一次分享的 ppt。


1. 從開發體驗角度來看:fiber/coroutine 自然是比回調好,但現在 nodejs 稍微有點經驗的人都會用 Promise, co,eventproxy 之類的東西吧。新的非同步解決方案只和 callback 比體現不了價值。個人認為長遠來說 ES7 async/await 勝過 coroutine,因為 a) 是 ES6 特性 (Promise, generator) 和社區最佳實踐的自然延伸; b) await 關鍵字讓同步和非同步調用有明確區分; c) 基於 traceur 預編譯可以跑在只支持 ES5 的瀏覽器里,利於前後端復用。d) 作為將來語言層面的特性,不依賴特定 runtime 底層實現。

2. fibjs 的性能優勢其實並不主要是因為 fiber,而更多來自於把 node 的 core lib 全部用 C/C++ 重寫了一遍。換句話說做同樣的事情,fibjs 更多的部分是跑在 C/C++ 實現的工作線程里,而不是在 js 的執行線程里。這個思路確實是提升性能的好方法,不過 node 如果把 core lib 全部用 C++ 重寫是否也能得到類似的性能提升呢?另外,fibjs 的性能提升主要是在 cpu 上,對於 database I/O bound 的應用來說是否依然有這麼大的差別?這一塊我不在行,希望有高人補充下。

3. 和 Node 生態圈的不兼容是個比較大的缺陷。所以說到底,用不用 fibjs 是在 Node 的生態圈和高性能之間的一個抉擇。對於追求極致性能、喜歡自造輪、且還沒有對 Node 作出太多投資的公司來說,是一個可以考慮的選擇。當然如果 fibjs 社區運營做得好,將來自己的生態圈繁榮起來了,跟 Node 一較長短也不是不可能。


當年 node.js 的作者之所以選擇 js 而不是其他語言,正是怕其他語言豐富的同步庫是累贅。

現在 node.js 的 npm 對於 fibjs 來說,是不可超越的。所以 npm 每多一個庫,fibjs 的推動就每受一點阻礙。

除非 fibjs 想辦法讓 npm 包可以無縫被使用,否則我認為,不值得投入精力學習。

我有那精力學一門新的後端 js 還不如直接轉 golang。

而且 fibjs 的非同步方式與前端 js 也不一樣,根本不懂它們選擇 js 的原因是什麼。


@響馬 你還不如做一個 callccjs。沒錯就是那種存整個堆棧的 call/cc。做出來絕壁功德無量。


fibjs剛嶄露頭角的時候我就偷偷關注了

在JS里實現了類似coroutine的同步非阻塞編程方式,比回調是方便多了,比yield/generator,async/await(我個人很喜歡)有見仁見智的意思,不展開討論。

但個人不是很能接受這種同步代碼,因為雖然代碼都是同步了,但是開發過程中事實上除非對每個函數實現都了解,否則很難掌握每一行代碼到底會不會掛起fiber,或者說,不知道每個函數到底有多大的代價。也許你以為這是個網路請求,調用了可以安心掛起fiber,但其實它是一個readFileSync,或者是個大循環?

相比之下,現在基於回調的各種寫法,比如Promise,比如async.js,是能夠很顯式的控制住一段程序的並行程度的。

而從 @響馬 的PPT里(我沒去今年D2現場)我卻看不出來在 fibjs程序裡面怎麼調用多個並行IO,也許是PPT沒體現出來?

C# 5.0中的async/await結合它的Task類各種方法,控制並行度也是比較輕鬆的。

yield/generator我沒在實際項目里用過,不過就初步接觸而言,似乎感覺yield很容易造成並行度模糊,比如return yield [a(), b(), c()]和return [yield a(), yield b(), yield c()]我就分不清,也理解不了,真幹上活肯定要踩坑……

不管是否阻塞,能在JS里實現同步調用無疑是一件很爽的事情,寫JS終於也可以一瀉千里了,寫JS終於也可以sleep了。但是全同步的問題就是你不知道每個函數調用會發生什麼了,有多大代價了。我個人感觸比較深刻的一點就是寫PHP的時候各種同步各種爽,但是我想做一個並行curl就……也許有curl_multi?是吧,但是curl_multi是不是又太粗放了呢,也許我並行請求abc,但是希望a出來的是先chunked出一段內容呢?我完全沒有這麼細粒度的控制權了。

說到底還是——對於 @響馬所說「我不認為讓開發者關心一個調用是同步還是非同步是一件好事情」我就不敢苟同……我希望我能更好的了解,進而控制我的程序的運行過程。而這樣粗放地簡化語言,也許會讓它缺失了這個控制能力。


如果沒有 npm 的生態圈,那麼還不如都去用 golang 呢。而如果想重造一個生態圈,那麼就需要有比現在的性能(現在 nodejs 的性能並不是痛點)和 coroutine (事實上,promise + co 已經把 callback 的問題緩解很多了) 更吸引人的賣點(現在 finjs 解決的問題,在 golang 里也是解決了的,而 golang 只是生態圈和應用場景比 JS 要弱很多,可預見的幾年,golang 在這方面也不可能有超越 JS 的機會)。


一句話:coroutine(fiber)對開發者要求比較高

對於一套代碼 可以用在nodejs fiberjs中 我覺得不是啥大問題,以後可能會有不同的js服務端引擎(不單單是node, fiber),但是不同的引擎應對不同的應用,但是使用的是是同一套代碼。


後端程序的話應該大部分是同步,小部分非同步,fibjs上應該是迎合了這個習慣。至於性能,由於沒有真正玩過,不好評價。mtjs/mt · GitHub


nodejs基於一些性能原因拒絕了實現coroutine, 而fibjs實現了coroutine, 然而fibjs的所謂的測試優於nodejs的結果依賴的是大量使用C++組件. 所以我個人對fibjs的性能存疑.


要是和NODEJS能夠 兼容早就火了,為什麼不和NPM兼容?


為了秀技術而敲代碼,為了博眼球而推廣。這樣的程序和程序員最後都gg了。。。


總體上支持響馬

  • 如果是nodejs中有較大的計算量,單線程會成為瓶頸,必須做cluster,額外增加的複雜度,但是用 fabjs 會好些,就是不存在並發衝突的大計算任務可以交給worker線程,還是不錯的。
  • 如果module完全按照AMD載入那就更好了,可以做到在運行中動態的按需載入模塊
  • 不過,js 最根本的問題還是既然決定要徹底的非阻塞,最終選擇什麼執行流控制方案,還是不能確定,同步式的代碼寫的簡單但是對細節控制差,其他方式寫法都繁瑣但是控制力夠強。


Breakpoint 1, fibjs::Socket::asyncSend::process (this=0x7fffec001640) at /home/jiangling/workspace/fibjs/fibjs/src/net/Socket_ev.cpp:471
471 while (m_sz)
(gdb) bt
#0 fibjs::Socket::asyncSend::process (this=0x7fffec001640) at /home/jiangling/workspace/fibjs/fibjs/src/net/Socket_ev.cpp:471
#1 0x00000000005b9beb in fibjs::asyncProc::call (this=0x7fffec001640) at /home/jiangling/workspace/fibjs/fibjs/src/net/Socket_ev.cpp:121
#2 0x00000000005bad66 in fibjs::Socket::send (this=0x7fffe8000be0, data=0x7fffec001350, ac=0x7fffec000e80)
at /home/jiangling/workspace/fibjs/fibjs/src/net/Socket_ev.cpp:512
#3 0x00000000005bb623 in fibjs::Socket::write (this=0x7fffe8000be0, data=0x7fffec001350, ac=0x7fffec000e80)
at /home/jiangling/workspace/fibjs/fibjs/src/net/Socket.cpp:117
#4 0x00000000004dd508 in fibjs::asyncSendTo::header (pState=0x7fffec000e80, n=0) at /home/jiangling/workspace/fibjs/fibjs/src/http/HttpMessage.cpp:84
#5 0x0000000000498f87 in fibjs::asyncState::post (this=0x7fffec000e80, v=0) at /home/jiangling/workspace/fibjs/fibjs/include/ifs/../AsyncCall.h:117
#6 0x00000000004dd6f4 in fibjs::HttpMessage::sendTo (this=0x7fffd8012be0, stm=0x7fffe8000be0, strCommand=..., ac=0x7fffd80126f0)
at /home/jiangling/workspace/fibjs/fibjs/src/http/HttpMessage.cpp:130
#7 0x00000000004d5b5a in fibjs::HttpResponse::sendTo (this=0x7fffd8012b50, stm=0x7fffe8000be0, ac=0x7fffd80126f0)
at /home/jiangling/workspace/fibjs/fibjs/src/http/HttpResponse.cpp:261
#8 0x00000000004bcc9d in fibjs::HttpHandler::asyncInvoke::send (pState=0x7fffd80126f0, n=0)
at /home/jiangling/workspace/fibjs/fibjs/src/http/HttpHandler.cpp:295
#9 0x0000000000498f87 in fibjs::asyncState::post (this=0x7fffd80126f0, v=0) at /home/jiangling/workspace/fibjs/fibjs/include/ifs/../AsyncCall.h:117
#10 0x0000000000498f4e in fibjs::asyncState::post (this=0x7fffe4023d20, v=100000) at /home/jiangling/workspace/fibjs/fibjs/include/ifs/../AsyncCall.h:111
#11 0x0000000000498f4e in fibjs::asyncState::post (this=0x7fffe4024140, v=100000) at /home/jiangling/workspace/fibjs/fibjs/include/ifs/../AsyncCall.h:111
#12 0x00000000005461c6 in fibjs::JSHandler::asyncInvoke::invoke (this=0x7fffe4024140) at /home/jiangling/workspace/fibjs/fibjs/src/mq/JSHandler.cpp:196
#13 0x0000000000615717 in fibjs::_acThread::Run (this=0x1929700 &) at /home/jiangling/workspace/fibjs/fibjs/src/base/acPool.cpp:57
#14 0x000000000061a161 in exlib::ThreadEntry (arg=0x1929700 &) at /home/jiangling/workspace/fibjs/vender/exlib/src/thread.cpp:18
#15 0x00007ffff77b80a5 in start_thread (arg=0x7ffff60e3700) at pthread_create.c:309
#16 0x00007ffff71dfcfd in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:111
(gdb) f 0
#0 fibjs::Socket::asyncSend::process (this=0x7fffec001640) at /home/jiangling/workspace/fibjs/fibjs/src/net/Socket_ev.cpp:471
471 while (m_sz)
(gdb) p m_p
warning: RTTI symbol not found for class "fibjs::Socket::send(fibjs::Buffer_base*, exlib::AsyncEvent*)::asyncSend"
$6 = 0x7fffec001408 "HTTP/1.1 200 OK
Cache-Control: no-cache, no-store
Expires: -1
Connection: keep-alive
Content-Length: 445

var koa = require("koa");
var Promise = require("bluebird");
//創建 promise ", &...
(gdb) p m_sz
warning: RTTI symbol not found for class "fibjs::Socket::send(fibjs::Buffer_base*, exlib::AsyncEvent*)::asyncSend"
$7 = 557
(gdb) info threads
Id Target Id Frame
9 Thread 0x7fffdf7fe700 (LWP 11631) "fibjs" sem_wait () at ../nptl/sysdeps/unix/sysv/linux/x86_64/sem_wait.S:85
8 Thread 0x7fffdffff700 (LWP 11630) "fibjs" 0x00007ffff71a6e0d in nanosleep () at ../sysdeps/unix/syscall-template.S:81
7 Thread 0x7ffff48e0700 (LWP 11629) "fibjs" 0x0000000000479902 in exlib::atomic::CompareAndSwap (this=0x19296c8 &, old_value=0,
new_value=0) at /home/jiangling/workspace/fibjs/fibjs/../vender/exlib/include/utils.h:69
6 Thread 0x7ffff50e1700 (LWP 11628) "fibjs" 0x00007ffff77bee1d in close () at ../sysdeps/unix/syscall-template.S:81
5 Thread 0x7ffff58e2700 (LWP 11627) "fibjs" 0x00007ffff77bee1d in close () at ../sysdeps/unix/syscall-template.S:81
* 4 Thread 0x7ffff60e3700 (LWP 11626) "fibjs" fibjs::Socket::asyncSend::process (this=0x7fffec001640)
at /home/jiangling/workspace/fibjs/fibjs/src/net/Socket_ev.cpp:471
3 Thread 0x7ffff68e4700 (LWP 11625) "fibjs" 0x00007ffff71e02d3 in epoll_wait () at ../sysdeps/unix/syscall-template.S:81
2 Thread 0x7ffff70e5700 (LWP 11624) "fibjs" sem_wait () at ../nptl/sysdeps/unix/sysv/linux/x86_64/sem_wait.S:85
1 Thread 0x7ffff7fd1780 (LWP 11620) "fibjs" 0x00007ffff71a6e0d in nanosleep () at ../sysdeps/unix/syscall-template.S:81
(gdb)

//測試代碼
var http = require("http");
var coroutine = require("coroutine");
var fs = require("fs");
var svr = new http.Server(30002, function(req) {
var rep = req.response;
rep.body.write(fs.readFile("server.js"));

});

svr.run();

這裡沒有對fibjs的任何不屑,只是好奇和驚喜。有一個疑問fibjs的高性能個人看主要來源於額外的線程池處理模型,而非協程。

1)如上主線程1並沒有在工作,和node.js有較大的差異;

2)網路發送,也就是這裡的http應答由線程4處理, 但還是屬於線程池中的線程,而不是libev線程,這裡是關鍵所在;

3)readFile由線程池s_acPool接管。

是不是可以說fibjs採用了多線程處理,而node.js是單線程處理模式. CPU對比上也是300%:120% , 性能對比上是否有作弊的嫌疑?@響馬@庄恆飛


看了一下介紹,這種自說自話的投機取巧的文案真是夠了。介紹自己非要拿各種精心安排的case去比較。我就說一句,難道編程是買保險嗎?買了不能退嗎?花言巧語即使騙來用戶真的有意義嗎?


這種赤裸裸的嘲諷同類產品進而推廣自己的做法讓人生厭


推薦閱讀:

Promise then中回調為什麼是非同步執行?
既然 Node.js 是單線程,又是怎麼做到支持非同步函數調用的?
vuejs怎麼在伺服器部署?
node.js和前端js有什麼區別?需要重新學習嗎?
typescript調用js(node)組件,必須在每一個引用的地方都寫reference嗎?

TAG:軟體開發 | JavaScript | 後端技術 | Nodejs | fibjs |