动态HTTP服务器极限性能,分为两项:
服务器
CPU:8核(4sockets*2cores),每核2.1GHz
内存:24GB
客户端(10个)
CPU:1核,每核2.1GHz
内存:1GB
测试流程:
3个版本的fibjs,分别为:
QPS(req/sec)
\ | v0 | v2 | v3 |
---|---|---|---|
10000 | 12750 | 15971 | 17705 |
20000 | 12757 | 15480 | 17893 |
30000 | 12551 | 15362 | 18045 |
40000 | 11858 | 15087 | 17326 |
50000 | 11678 | 15503 | 17237 |
60000 | 11708 | 15093 | 16800 |
70000 | 10682 | 14674 | 16513 |
80000 | 9395 | 14223 | 15840 |
90000 | 8733 | 13681 | 15209 |
100000 | 8645 | 13375 | 14664 |
QPS曲线如下图:
内存占用(单位GB)
\ | v0 | v1 | v2 |
---|---|---|---|
10000 | 1.55 | 0.37 | 0.14 |
20000 | 2.95 | 0.68 | 0.22 |
30000 | 4.32 | 1.05 | 0.27 |
40000 | 5.82 | 1.32 | 0.35 |
50000 | 7.27 | 1.63 | 0.41 |
60000 | 8.79 | 1.89 | 0.47 |
70000 | 10.15 | 2.32 | 0.53 |
80000 | 11.57 | 2.63 | 0.6 |
90000 | 13.03 | 2.98 | 0.67 |
100000 | 14.5 | 3.36 | 0.79 |
内存占用曲线如下图:
服务器分别为:
QPS(req/sec)
\ | fibjs | nodejs | go | nginx |
---|---|---|---|---|
10000 | 17705 | 8268 | 22284 | 19393 |
20000 | 17893 | 5866 | 21975 | 19096 |
30000 | 18045 | 4412 | 21531 | 18521 |
40000 | 17326 | 2817 | 21362 | 18331 |
50000 | 17237 | 2179 | 21277 | 18328 |
60000 | 16800 | 1853 | 21113 | 17936 |
70000 | 16513 | 1536 | 21029 | 17644 |
80000 | 15840 | 1385 | 20497 | 16973 |
90000 | 15209 | 1232 | 19843 | 16966 |
100000 | 14664 | 1089 | 19386 | 16805 |
QPS曲线如下图
内存占用(单位GB)
\ | fibjs | nodejs | go | nginx |
---|---|---|---|---|
10000 | 0.14 | 0.56 | 0.37 | 0.1 |
20000 | 0.22 | 0.68 | 0.68 | 0.1 |
30000 | 0.27 | 0.76 | 1.05 | 0.11 |
40000 | 0.35 | 0.84 | 1.32 | 0.12 |
50000 | 0.41 | 0.92 | 1.63 | 0.12 |
60000 | 0.47 | 1.02 | 1.89 | 0.12 |
70000 | 0.53 | 1.08 | 2.32 | 0.13 |
80000 | 0.6 | 1.14 | 2.63 | 0.13 |
90000 | 0.67 | 1.3 | 2.98 | 0.14 |
100000 | 0.79 | 1.45 | 3.36 | 0.14 |
内存占用曲线如下图
服务器CPU占用情况
\ | fibjs | nodejs | go | nginx |
---|---|---|---|---|
CPU占用率 | 500~600 | (90~98)*8 | 200~400 | (30~35)*8 |
模型
内存占用
QPS
var http = require('http'),
net = require('net'),
coroutine = require('coroutine');
var interval = 1000;
var hdlr = new http.Handler(function(req) {
if (req.address == "/fibjs") {
req.response.write('Hello, World!');
}
})
var demon = function() {
while (true) {
console.error("connections:", svr.stats.connections,
"\trequest:", hdlr.stats.request,
"\tresponse:", hdlr.stats.response);
hdlr.stats.reset();
svr.stats.reset();
coroutine.sleep(interval);
}
}
var svr = new net.TcpServer(8080, hdlr);
coroutine.start(demon);
svr.run();
var cluster = require('cluster'),
http = require('http'),
url = require('url'),
numCPUs = require('os').cpus().length;
if (cluster.isMaster) {
console.log("master start...");
// Fork workers.
for (var i = 0; i < numCPUs; i++) {
cluster.fork();
}
cluster.on('listening', function(worker, address) {
console.log('listening: worker ' + worker.process.pid + ', Address: ' + address.address + ":" + address.port);
});
cluster.on('exit', function(worker, code, signal) {
console.log('worker ' + worker.process.pid + ' died');
});
} else {
http.createServer(function(req, res) {
var pathname = url.parse(req.url).pathname;
if ("/node" === pathname) {
res.writeHead(200);
res.end("Hello World!\n");
}
}).listen(8080);
}
package main
import (
"net/http"
"runtime"
"log"
)
func hdlr_hello(rw http.ResponseWriter, req *http.Request) {
req.ParseForm()
rw.Write([]byte("Hello world!"))
}
func main() {
runtime.GOMAXPROCS(runtime.NumCPU())
http.HandleFunc("/go", hdlr_hello) //设置访问的路由
err := http.ListenAndServe(":8083", nil) //设置监听的端口
if err != nil {
log.Fatal("ListenAndServe: ", err)
// panic(err)
}
}
#include
#include
#include
#include
/*
*cf 指向ngx_conf_t 结构体指针,从指令后面传过来的参数
*cmd 指向当前结构体ngx_command_t 的指针(互相指)
*conf 指向自定义模块配置结构体的指针
*/
static char *ngx_http_hello_world(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
static ngx_command_t ngx_http_hello_world_commands[]={
{
ngx_string("hello_world"), //指令名称,nginx.conf中使用
NGX_HTTP_LOC_CONF|NGX_CONF_NOARGS, //注释1
ngx_http_hello_world, //回调函数,上面申明
0, //保持的值存放位置:全局,server,location
0, //指令的值保存位置
NULL
},
ngx_null_command //读入ngx_null_command 指令后停止
};
//ngx_http__module_ctx用于创建和合并三个配置
static ngx_http_module_t ngx_http_hello_world_module_ctx={
NULL, //preconfiguration
NULL, //postconfiguration
NULL, //create main configuration
NULL, //init main configuration
NULL, //create server configuration
NULL, //merge server configuration
NULL, //create location configuration
NULL //merge localtion configuration
};
//nginx进程,线程相关,ngx_http__module把数据处理关联到特定模块
ngx_module_t ngx_http_hello_world_module={
NGX_MODULE_V1,
&ngx_http_hello_world_module_ctx, //module context
ngx_http_hello_world_commands, //module directives
NGX_HTTP_MODULE, //module type
NULL, //init master
NULL, //init module
NULL, //init process
NULL, //init thread
NULL, //exit thread
NULL, //exit process
NULL, //exit master
NGX_MODULE_V1_PADDING
};
static ngx_int_t ngx_http_hello_world_handler(ngx_http_request_t *r)
{
if(!(r->method & NGX_HTTP_GET))
return NGX_HTTP_NOT_ALLOWED;
ngx_int_t rc = ngx_http_discard_request_body(r);
if(rc != NGX_OK)
return rc;
ngx_str_t type = ngx_string("text/plain");
ngx_str_t response = ngx_string("Hello World!");
r->headers_out.status = NGX_HTTP_OK;
r->headers_out.content_length_n = response.len;
r->headers_out.content_type = type;
rc = ngx_http_send_header(r);
if(rc == NGX_ERROR || rc > NGX_OK || r->header_only)
return rc;
ngx_buf_t *b;
b = ngx_create_temp_buf(r->pool, response.len);
if(b == NULL)
return NGX_HTTP_INTERNAL_SERVER_ERROR;
ngx_memcpy(b->pos, response.data, response.len);
b->last = b->pos + response.len;
b->last_buf = 1;
ngx_chain_t out;
out.buf = b;
out.next = NULL;
return ngx_http_output_filter(r,&out);
}
//回调函数,1获得location中的“核心”结构体,2为他分配个处理函数
static char *ngx_http_hello_world(ngx_conf_t *cf,ngx_command_t *cmd,void *conf)
{
ngx_http_core_loc_conf_t *clcf;
clcf = ngx_http_conf_get_module_loc_conf(cf,ngx_http_core_module);
clcf->handler = ngx_http_hello_world_handler;
return NGX_CONF_OK;
}
###脚本_集群调度
#!/usr/bash
if [ $# -lt 1 ]; then
echo ""
echo "option [conn | close]"
echo ""
exit 0
fi
user=verdant
concurrency=50000
duration=600
logdir="log/"
logfile="ctrl.log."
ip_array=("171" "193" "209" "213" "231" "219" "222" "223" "224" "225")
conn=$(($concurrency/${#ip_array[*]}))
sleeptime=1
# sleeptime=$(($concurrency/10000+1))
remote_cmd="~/wrk -t10 -c$conn -d""$duration""s http://192.168.1.61:8080/fibjs"
# remote_cmd="~/wrk -t10 -c$conn -d""$duration""s http://192.168.1.61:8080/node"
# remote_cmd="~/wrk -t10 -c$conn -d""$duration""s http://192.168.1.61:8080/go"
# remote_cmd="~/wrk -t10 -c$conn -d""$duration""s http://192.168.1.61:8080/nginx"
function main()
{
echo "${#ip_array[*]} client each: $conn"
for ip in ${ip_array[*]}
do
if [ -e "$logdir$logfile$ip" ]; then
rm "$logdir$logfile$ip"
fi
done
if [ $1 = 'close' ]; then
for ip in ${ip_array[*]}
do
result=$(ssh -t -t $user@"192.168.1."$ip "killall -9 wrk">> $logdir$logfile$ip &)
sleep "$sleeptime"
echo $result
done
exit 0
fi
if [ $1 = 'conn' ]; then
for ip in ${ip_array[*]}
do
ssh -t -t $user@"192.168.1."$ip "$remote_cmd">> $logdir$logfile$ip &
sleep "$sleeptime"
done
fi
}
function recovery()
{
running=0
server_ok=()
while [ $running -ne ${#ip_array[*]} ]
do
for ip in ${ip_array[*]}
do
if [ ! -s "$logdir$logfile$ip" ]; then
echo "restart:""$logdir$logfile$ip"
sleep $((5*$sleeptime))
ssh -t -t $user@"192.168.1."$ip "killall -9 wrk"
sleep $((10*$sleeptime))
ssh -t -t $user@"192.168.1."$ip "$remote_cmd">> $logdir$logfile$ip &
else
if [[ "${server_ok[@]/$ip/}" = "${server_ok[@]}" ]]; then
server_ok[${#server_ok[@]}]=$ip
running=$(($running+1))
fi
fi
done
done
}
function calculate()
{
result1=0
result2=1
while [ $1 = 'conn' -a $result1 != $result2 ]
do
result1=`cat $logdir$logfile*|grep Requests/sec|awk '{print $2}'|awk '{sum+=$1} END {print sum}'`
if [ "$result1" = "" ]; then
result1=0
sleep 10
continue
fi
sleep 10
result2=`cat $logdir$logfile*|grep Requests/sec|awk '{print $2}'|awk '{sum+=$1} END {print sum}'`
done
echo "Requests/sec: $result1"
cat $logdir$logfile*|grep Latency
}
main $1
sleep $((${#ip_array[*]}*$sleeptime))
#客户端异常重连机制
if [ $1 = 'conn' ]; then
recovery
fi
sleep $duration
echo "calculate..."
calculate $1
node用0.10、、、、、
@i5ting 会有差别吗?
@xicilion 会的,用4.2或5.x
@i5ting 估计会有多大差别?提升 100% 还是提升 1000%?提升 100% 以内就不麻烦再测试一遍了。
赞一个
然而生态、、、、、
不可否认node的确曾经依靠纯异步有不错的性能表现,但现在要讲高性能,这得看跟谁比了,跟同步比那还能算高性能的,但跟其他异步框架比起来,还能说是高性能么?从测试成绩来看,顶多算还行,就算用4.2,5.x来测,结果也好看不到哪里去,至少不会出现数量极的改变。
现在node社区的人,唯一可以自慰的就是生态了,为什么会这样?因为性能已经不好意思拿来吹了。
感谢响马大哥的测试。
支持国产是重点
定位要准确,没有一种语言是万金油,选择适合自己的
nodejs 代码里 var pathname = url.parse(req.url).pathname;
这句可以省掉,直接用"/node" === req.url
很详细很赞的测试,我只能膜拜了。说说几点我的观点吧。
对楼主还是敬佩的。上面所列的几点只不过我站在客观角度所言。
做这个测试的原因当然是出于是业务需要,有一些业务场景是需要维持大量连接而运算量并不大的。
测试过程中也有两次对 fibjs 优化的结果。
最初并没有打算测试 nodejs,因为知道它肯定抗不住。但是考虑到发出来肯定有人会问 nodejs 的数据,就特意测了一份来。做出来才知道,nodejs 比我能想象的更差劲。一万以内,fibjs 是它的 2 倍,到 10 万的时候,已经是它的 15 倍了。就这点性能还启用了 cluster。
至于招人,还真不难,校招新人一周内上手,比 nodejs 快多了,而且基本不会写错代码。
@flyingcodes
fibjs的思想还是非常值得学习的,利用协程隐藏回调,实现形式同步,实质异步。形式同步是大势所驱,编程模型应该越简单越好,这不仅仅对nodejs,对其他所有技术都一样。@xicilion 大哥的公司能够在大学里招人过来,一个礼拜上手,本身就说明了这点。学校里教的就是同步编程,业务大多也是同步需求。
显式的异步代码对异步本身的发展就是阻碍。我们只需要异步带来的性能好处,但并不需要由此引入的编程复杂度。
@xicilion 为何还不干掉go那个我讨厌的语言
@coordcn 虽然我掉进了回调的坑,但是我觉得掉的还蛮值得的。不管代码层面异步还是同步,我个人觉得没关系,而且通过异步代码的编写我多少了解了一点异步回调隐藏的方法。如果fibjs雄起甚至干掉nodejs也是蛮好的。如果确实性能突出, 而且生态好的话,必须用!大大们多做做实验吧~撇开这个测试不说,希望响马能多广告发扬一下fibjs,让广大编程工作者来检验一下,要是真把nodejs屁股给踢疼了,我觉得应该很赞!
@DevinXian
对异步理解到了一个程度,异步的形式已经不重要了,这个时候追求的应该是非显式的异步,就像武功高强的人达到无招胜有招的境界。很多原来同步的语言,现在通过改进后,nodejs已经没有任何性能优势了,如果继续抱着原有的编程模型不放,只会越来越落后。
node在阿里的应用也仅仅限于大前端,阿里的人自己在之乎上说核心交易nodejs成绩为0。这里的原因,我想,java成熟稳定是一方面,nodejs显示异步的编程模型和业务同步逻辑之间的矛盾才是最主要的。核心交易业务复杂的程度,不是简单的理解了回调,理解了异步就能应对的。你只要自己试着用nodejs写一个异步文件夹遍历,就可以想象在复杂业务条件下,显示的异步是多么的无力。
回调不能代表异步,如果你愿意,同步代码也可以用回调来表达。回调在异步程序中的作用恰恰是保证同步,保证执行顺序的。
回调模式下的异步,现在已经成为nodejs的包袱,generator和promise的缓和作用有限,学习成本还是有的,是典型的为了解决一个问题,又引入另外一个问题的做法。这些东西在前端是适用的,但面对复杂的后端,形式同步才是终极解决方案。
nodejs用来做demo,做一些大前端页面渲染是合适的,这些应用不涉及复杂的后端数据库交互过程,只要一两次异步就能搞定,阿里就是这么搞的,真正的后端将数据准备好,nodejs取过来,套上模板渲染传给浏览器。
@coordcn 多谢鸡汤。PS:你撸汉字快赶上我撸代码速度了0.0
@flyingcodes
fibjs的源代码我大致浏览过,实现思路也大致了解,细节没有深入。我更看重的是思路,有了思路,代码堆出来只是时间问题。
我自己也在利用libuv和lua实现一个形式同步的网络库,做这个事情,是去年受到fibjs的触动,我那时正好在写文件夹遍历,被回调搞得很爽,这个过程我就有了反思,后来也看了openresty的代码,我c++不行,fibjs,v8都玩不转,就选择了c + lua + libuv,lua天生提供协程支持,openresty又有现成的通过协程回调转同步代码参考,lua和javascript在本质上很相似,libuv读nodejs的源代码的时候看过,自己很喜欢,自然就用这个网络库了。整个框架已经搭好,中间重构了一次,马上就可以发布出来。
@DevinXian
那你写代码速度好快了,我除非写测试代码,不然一天也就顶多200行不到。
@coordcn 赞,期待中。。。
这样看go这么牛逼,要性能那直接上go,至少生态要好啊。
有对比,对语言,还是社区都是好事。@xicilion 可否有空翻成英文,发到 HN 等,看看社区反映。
fibjs确实不错,目前还属于极客,还需要时间吧。
@xicilion
跟响马大哥的fibjs是没法比的,整个项目还很原始,但是通过协程异步转同步的思路还是表达出来了。fibjs的让我对异步有了更进一步的认识,同步代码才是异步程序的最终归宿,编程思想才是最重要的,非常感谢引路人响马大哥。
我c++水平太次,只能看懂代码,自己写不行,无奈只好用c+lua来实现,无法为fibjs做什么贡献。
其实你们可以把fibjs理解为一个能运行v8的框架,这个框架包括了文件数据库网络等等的东西node理解为一个封装有常用系统api和其它一些常用类库的服务端用的js运行时 只不过js引擎用的v8 其实也可以换成其他的比如微软就换成查克拉了 其它有些人换成spidermonkey了nodejs 和 fibjs 差不多的地方就是都碰巧选用了v8而已
@jiangzhuo fibjs 选 v8 倒不是碰巧,spidermonkey 和 JavascriptCore 都不能很好地支持 fiber,只有 v8 能够兼容这个模式。微软的引擎向来支持多线程,应该可以使用,但是跨平台是个问题。
因此 fibjs 最终选择了 v8。nodejs 对引擎依赖比较小,倒是可以很方便移植,几个 Javascript 引擎都有移植的版本。
@coordcn 看是什么代码了,哈哈,我指的其实是字符数!
我想知道nodejs以后有没有性能提高的可能,在现有架构下,毕竟前端工程师不想放弃npm丰富的支持
fibjs好像很有趣。我去看看。
与其唱双簧,还是希望能把官网的引导做好一点。(官网打开很慢,jquery的content-download时间20s,也不知道是网络问题还是服务器问题还是我的浏览器爆炸了)
用nodejs其实没别的,就是生态太完善了,想要的库基本上都有,再加上性能也还可以。最大的问题就是异步。成也异步败也异步,不过现在也已经有比较好的方案再解决这个问题。至于性能,很多时候说实话不是最关键,初创企业能有几个项目真能一开始就碰到太多性能问题,开发效率和速度才是最关键啊。
统一回复:
@dlutwuwei没有可能。
@lingmm一、中间有几个版本在 32 bits 上运行是会出错,我们没做好全平台测试,一直也没有人回报,目前已经发现并修复了二、vs2015 稍微转换即可编译,而设置为 vs2015,vs2013 却肯定不能编译了。windows 版本仅为兼容,虽然性能同样很好,但是我们自己并没有大量使用,虽然我知道有公司在 windows 上投入生产环境,但是我们没有一手数据,所以不建议生产环境使用,做做测试尚可三、人力所限,不提供二进制下载,如果是 mac,可以通过 brew install fibjs 直接安装四、文档是萝卜青菜,各有所爱,大家都是程序员,就别在那些虚头巴脑的文字上纠结了,直接干代码就好了五、官网慢是因为 vps 慢,建议从 github 下载 docs 本地阅读,国内 vps 还要备案,烦躁
@arden文无第一,武无第二,大家都是程序员,快就是快,不快就是不快。你看我就从来不辩解说生态不重要,没有就是没有。
我记得我去年在这里就看到,楼主发测试了。今年又是测试。。。对,fibjs快!
楼主大神,弄的我都不想学node了,好样的
佩服楼主的功力,但是还是不看好。
每次看到楼主的帖子就想放弃nodejs,还是安心做一个前端吧,想当初在java的泥潭里受不了,转前端也就是因为nodejs才下定决心
@dlutwuwei 为啥要放弃,是因为你觉得楼主太厉害了吗。。。
我的乖乖
这种贴,评论永远比正文更精彩
@xicilion 我觉得既然你们在这里发贴子,肯定也有想推广的心吧。能够看到更多的人使用才能证明他开源的成功不是。不然自己藏着就好了。。既然说文档不重要,那多做点demo啊=。=
@lingmm http://fibjs.org 有全套文档,代码目录的 test 内有每一个对象与模块的每一个 api 的使用用例。
什么时候分享一下测试的东西
又见hello world测试。。。毫无意义。。。
你提到了go.可以去试试这个,https://github.com/valyala/fasthttp性能是标库http的5倍以上。但有什么意义?
@alanyang
别人的工作怎么会毫无意义呢?一些人总喜欢纠结于测试本身的结果,而忽略了为什么会有这样的结果,也就是它快,但为什么这样快呢?
@xicilion 不但给出了具体的测试方法和代码,还告诉大家优化的过程和思路,这个过程和思路才是真正的精华所在。服务器优化到极至,拼的就是内存的使用效率,不该分配的地方绝对不重新分配,不该拷贝的地方绝对不做无谓的拷贝,可以重用的尽量重用。这些方法其实都是通用的优化方案,这些工作我认为是非常意义的。
fasthttp优化的原理也是大致相同的,同样是减少重新分配,少拷贝,多重用。
fibjs和go相对于nodejs而言,更重要的意义就是使得nodejs不得不朝更加易用的形式同步编程模式演化,把回调异步的神话打破。想当初nodejs是多么痴迷回调异步,拒绝引入协程,结果活生生被ES6打脸了,还闹出了分裂逼宫的闹剧,要想舒舒服服的写异步程序,协程是绕不过去的,即便是async/await还很低级,更不要说ES6了。当有的人看到一些人老早就在用同步代码写异步程序的时候,你就会觉得有的人的工作是意义大去了,这个意义不在代码本身,而在思想。
你所做的性能改进为什么不在nodejs上做呢?走分裂的路不对,添砖加瓦才有前途。
@gzhangzy 根本不是一个路线,没办法添啊。况且fibjs刚出来的时候,nodejs回调异步还如日中天,人根本看不上协程这种路线,虽然现在nodejs也事实上走了类协程路线,最终还是会发展成跟fibjs类似的形式同步,实质异步。nodejs加个新特性都要闹分裂,逼宫,fibjs这么激进的方式他们根本不会接受。
很奇怪,go语言有这么多如此优秀的框架,为什么网上总是有人批判go语言不好。
感觉fibjs在javascript语言里很牛逼啊,但总觉得在这里贬低nodejs没有什么用
我想问的是,前端web界面里面,ajax,可以用这种"协程", 的方式来编程吗? 很多应用,前端也是有很多逻辑的
@151263 http://blog.csdn.net/kobejayandy/article/details/11856735 这个是“协程”的概念的,node里面有async支持协程,前台里面应该是promise这个库来支持的吧(不知道理解的对不对o(╯□╰)o)
@coordcn我还是坚持我的观点,hello world无意义。纯浪费时候。。
最少加点template render, session in cookies之类cpu运算。最少得加点io操作模拟可能的阻塞吧。
这种测试和http paser + epoll测试有什么区别?
有个小故事,go界有个最近吹得很厉害的框架iris,自称性能秒杀标库http。。当然他自己测试用的也是hello world :)后来有人加了些许线上常出现的业务代码,性能下降到连martini不如,沦为笑柄。后来看代码才知道,这货是取巧缓存了context,当无阻塞时候,那当然快得很。但线上情况可能吗?
对于你说的引入coroutine的优势,还是认可的。
@arden语言太朴实,没花头。。
@alanyang 无话可说,不谈性能,不谈生态,就是喜好~
http://www.jdon.com/47912这篇文章说,“协程”, 是有问题的
—有时,回调函数反而更加强大,虽然,goroutine协程口口声声说是用来替代万恶的回调函数的。协程只是比线程较为轻量,但是较为轻量不代表它是最轻量的。
@alanyang
我已经说过了,高性能服务器在不动内核的前提下,大家最后比的就是内存使用效率,同样原理,不同的代码,性能差距还是有的,helloworld就是为了排除其他影响,测试纯粹的网络性能的。这个东西不能代表性能的全部,但也是一个比较重要的指标。nodejs当初不也是helloworld起家的?
个别人做helloworld测试不严谨,投机取巧,甚至作弊,也不能证明helloworld测试性能就毫无意义啊,这个基本的逻辑关系,我想程序员都应该能够搞清楚的。你如果看过V8的源代码,就会明白缓存是一个非常重要的优化手段,不必要的计算不计算,这本身就是一种非常重要的优化思想。
我们需要谴责的是那种为了数据漂亮,不择手段的测试,像响马这样的测试,我觉得不是属于这种。但必须要明白,这些测试也仅仅对测试代码负责,并不能代表全部性能。框架性能再好,也架不住业务代码过分烂啊。但如果框架性能好点,业务代码的性能压力相对要小一些。
@151263
协程相对于纯粹的回调性能会差点,协程切换还是要保存CPU寄存器的,跟函数调用的代价比还是比较大的。
协程比回调优势的地方是在异步表达上,协程可以实现用同步代码编写异步程序,回调是无法做到的。
性能和编码效率在这里就是一对矛盾,现在已经证明纯粹的回调编码效率不行,javascript引入了generator/yield,async/await来缓解这个问题,但由于这两者背后还是基于回调,虽然代码局部同步了,但有的时候还是要用异步思维去写程序。javascript在纯粹的回调外又包装了一层,其性能很难说比协程有优势了。
我用C + lua5.3 + libuv 实现的异步框架luaio,TCP性能就比nodejs高一倍,luaio可以用完全同步的代码写异步程序。所以虽然理论上纯回调性能更好,但具体实现还要看实际情况。协程实现方法也有很多种,性能也不同。lua的是单线程setjmp/longjmp,fibjs是自己汇编实现的ucontext,go是多线程的。
选择什么样的异步编程模型,归根到底还是在编码效率和性能之间做个权衡,没有完全无懈可击的方案,只有适合自己的方案。
有空研究下fibjs的底层实现昨天也是偶然看到一个回复提到了fibjs,确实大开眼界
估计会有多大差别?提升 100% 还是提升 1000%?提升 100% 以内就不麻烦再测试一遍了。
用 0.10 做对比基本没什么参考价值,反倒误导了不少不留意的同学
goroutine协程本质上也是解决 io 密集型任务。其实就实现角度看,回调是基础,回调技术包含着闭包技术,闭包保存了打断的上下文,使得逻辑可以继续。现在 es6 的 generator 从 js 层面实现了,也可以从C++层面做这些事情,我觉得 fibjs 就是在 C++层面实现了,因为将异步代码写成同步的是大势所趋。
之前关注过fibjs,也非常看好它。很多小伙伴都有体会,从接触nodejs开始,大部分精力都耗费在如何通过同步的方法来写异步代码上了,现在连js都在语言层面来适应它,实在拧巴。fibjs从底层解决了这个问题,应该是很好的解决思路。有机会一定认真研究下fibjs,把亿书代码用fibjs实现一遍。
感觉又一波可以学
伟大的楼主,是否可以考虑再并行加上一个J2EE的跑分评测结果呀?这样的话,我就能对go, fibjs, nginx, J2EE有一个比较全面的评估了。还是说,J2EE跑分结果太低了,都不合适写到贴子里,再耽误功夫了。
文档感人,如果不把文档完善下的话,我不晓得有什么人敢用
fibjs支持server端的canvas(类似于node-canvas),我的项目里有需求:在后端合成图片。
大脸叔叔很厉害
node 应用范围确实要注意哦,如果国内有商家支持、咱们再给力积攒下生态fibjs 有希望哦;
有点理想化了