.NET 和 Node.js 的性能比较 已翻译 100%

oschina 投递于 2013/06/20 06:38 (共 7 段, 翻译完成于 06-26)
阅读 18898
收藏 55
5
加载中

修正于(2013年-3月-31日 下午11:41 标准时间)此文已经撰写完毕!在绝大多数读者眼里认为Node.js的异步包是无法实现异步的功能的,那么此文又该基于什么来写呢?我确信我不是这样所想的.我曾经想通过这个帐号进行测试,并将这些数据推荐到http://guillaume86.calepin.co/dotnet-vs-nodejs-performance.html这里去,我确信未来不会影响到已经存在的言论.谢谢你们每一个人的意见,使得我保持清醒

修正于(2013年-3月-29 下午3:43 标准时间)有许多的评论围绕NPM的async包来做验证,我也将在我的账号中从新测试.

独爱剑走偏锋
翻译于 2013/06/24 22:20
1
如果你今天和任何一个在硅谷的创业者交谈,你都有机会听到node.js。 由于强迫非阻塞IO, Node.js是快速,可扩展性,并且它高效地利用了单线程模型的诸多特性,也是人们争论最多的一个关键原因。我个人喜欢Javascript,所以能够在服务器端使用Javascript似乎是一个重要的收获。Node.js超级快,因为不存在上下文切换和线程同步。这一观念,实际上我并没有真正地赞同过。我们都知道,这些做法应该是在任何多线程程序要完全避免,但要放弃一切,似乎像一个极端。但如果这意味着持续的高性能,又能得到保障,那将是有意义的。所以,我想测试这些理论,我想尽可能地以经验为主地探明到底相比.NET,node.js是如何做到更快。
徐继开
翻译于 2013/06/25 08:43
1

于是乎,我提出了一个涉及IO(理论上不涉及数据库)和计算的问题。我想让它们处于负载,这样我就能看每个系统在压力下是怎样表现的。我提出了以下的问题:我有将近200个文件,每个文件在某在地方包含1万到3万个随机小数。每一次对服务器的请求都包含一个数字,例如/1和/120,服务器就会打开相应的文件,读取文件的内容,并完成在内存中的排序,然后输出中间值。对了,就是这样。我们的目标就是达到最大的200个同时发生的请求,在这样的想法下,每个请求都有一个对应的文件并且没有重叠。

我同样想让两个平台一致(.NET和Node.js)。举个例子,我并不想在IIS上搭载.NET,因为IIS带来的开销太大了(缓存,路由,性能计数器),如果我们以后都不用这些,那这样的花销就不公平了。我也避免了整个ASP.NET的管道,包括MVC,出于同样的原因,它们带来了我们在这个案例下不需要关心的特性。


徐继开
翻译于 2013/06/26 00:15
1

接下来,我们使用.NET和Node.js创建一个基本HTTP监听.那谁来做客户端呢?在这里我计划创建一个.NET控制台应用程序去访问我们之前创建的这两个HTTP服务.客户端是写的.NET之上的,使之我们的.NET和Node.js的服务都能够使用相同的客户端.在如此小规模的客户端访问是可以被忽略的问题.在我们研究更详细的问题之前,让我们看下面的结果图

.NET and Node.JS - Performance Comparison

在.NET和Node.js中性能访问记数(越低越好)

我们可以看到在平均情况下Node.js性能卓越.即使在少有的峰值出异常的情况下,一部分读者可能被其迷惑.我要澄清的是图中两条线在最后时刻有意思的测试,随着时间的推移你可能认为.NET和Node.js的性能总和甚至会超过.NET的启动时间,接下来让我们用不通的切面来进行更多的测试。

独爱剑走偏锋
翻译于 2013/06/25 10:41
1
我们将从客户端开始,客户端使用 HttpClient来驱动对服务器的请求。响应时间都是在客户端维持的,以至于服务器上不会出现极端的运行差异,也不会影响我们生成的数字。注意一点,不到最后一步,我是不会轻易做任何Console.Write。
publicvoidStart()
{
    Task[] tasks =newTask[this.tasks];
 
    for(inti = 0; i <this.tasks; ++i)
    {
        tasks[i] =this.Perform(i);
    }
 
    Task.WaitAll(tasks);
 
    result.ToList().ForEach(Console.WriteLine);
}
publicasync Task Perform(intstate)
{
    stringurl = String.Format("{0}{1}",this.baseUrl, state.ToString().PadLeft(3,'0'));
    var client =newHttpClient();
    Stopwatch timer =newStopwatch();
 
    timer.Start();
    stringresult = await client.GetStringAsync(url);
    timer.Stop();
 
    this.result.Enqueue(String.Format("{0,4}\t{1,5}\t{2}", url, timer.ElapsedMilliseconds, result));
}
有了这样的客户端,我们可以开始关注服务器端了。首先,我们开始用Node.js来实现了。Node.js的美在于它的简明的语法。我们能用区区不足40行的代码来来创建一些基于CPU核数的进程,并且能在它们上面共享受CPU限制的任务。
徐继开
翻译于 2013/06/26 20:54
1
var http = require('http');
var fs = require('fs');
var cluster = require('cluster');
var numCPUs = require('os').cpus().length;
 
if(cluster.isMaster) {
    // Fork workers.
    for(var i = 0; i < numCPUs; i++) {
        cluster.fork();
    }
 
    cluster.on('exit',function(worker, code, signal) {
        console.log('worker '+ worker.process.pid +' died');
    });
}
else{
    http.createServer(function(request, response) {
        var file = parseInt(request.url.substring(1));
        file = file % 200;
        file = String("000"+ file).slice(-3);
 
        // read the file
        fs.readFile('../data/input'+file+'.txt','ascii',function(err, data) {
            if(err) {
                response.writeHead(400, {'Content-Type':'text/plain'});
                response.end();
            }
            else{
                var results = data.toString().split("\r\n");
 
                results.sort();
                response.writeHead(200, {'Content-Type':'text/plain'});
                response.end('input'+file+'.txt\t'+ results[(parseInt(results.length/2))]);
            }
        });
    }).listen(8080,'127.0.0.1');
}
console.log('Server running at http://127.0.0.1:8080/')
最后,我们来看看.NET服务实现,确切的说我们用的是.NET 4.5版本,自带async/await功能。如我前面提到的一样,我希望用不带IIS或者ASP.NET的纯.NET来和node比较,所以我用一个简单的HTTP监听程序来开始:
publicasync Task Start()
{
    while(true)
    {
        var context = awaitthis.listener.GetContextAsync();
        this.ProcessRequest(context);
    }
}
通过这个我可以开始处理各个请求,请求一进来我读取文件流系统,并没有阻塞线程池里的线程,然后执行内存排序,这是用Array.Sort重写的一个简单任务。对于.NET,在这里通过参照并行编程写的并行排序算法使得程序有了显著的性能提升,但是我没有选择这样是因为这不是这两者比较的重点。
private async void ProcessRequest(HttpListenerContext context)
{
    try
    {
        var filename = this.GetFileFromUrl(context.Request.Url.PathAndQuery.Substring(1));
        string rawData = string.Empty;
 
        using (StreamReader reader = new StreamReader(Path.Combine(dataDirectory, filename)))
        {
            rawData = await reader.ReadToEndAsync();
        }
         
        var sorted = await this.SortAsync(context, rawData);
        var response = encoding.GetBytes(String.Format("{0}\t{1}", filename, sorted[sorted.Length / 2]));
 
        await context.Response.OutputStream.WriteAsync(response, 0, response.Length);
        context.Response.StatusCode = (int)HttpStatusCode.OK;
    }
    catch(Exception e)
    {
        context.Response.StatusCode = (int)HttpStatusCode.BadRequest;
        Console.WriteLine(e.Message);
    }
    finally
    {
        context.Response.Close();
    }
}
 
private async Task<string[]> SortAsync(HttpListenerContext context, string rawData)
{
    return await Task.Factory.StartNew(() =>
    {
        var array = rawData.Split(new string[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries);
        Array.Sort(array);
 
        return array;
    });
}
zhoujy
翻译于 2013/06/26 18:26
1

你能下载整个源代码,这个压缩文件包括了.NET和Node.js的客户端和服务器端的源代码。同时压缩包里还包括了生成随机数文件的工具,你能在你的本机中运行这些测试。你将在zip文件中发现这些原始的数字。

当你决定为你的服务器选择下一个框架的时候,我希望这些测试能对你有帮助。对于大多数创业者来说,最关键的支点是性能,拓展性。显然,Node.js在今天已经展现给我们了。

同时,请记住以下的一些评论是基于使用async NPM 包的原始文章。本文已更新了正确的信息。

徐继开
翻译于 2013/06/26 00:30
1
本文中的所有译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接。
我们的翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们。
加载中

评论(33)

a
a14907
public async Task Start()
{
while (true)
{
var context = await this.listener.GetContextAsync();
this.ProcessRequest(context);
}
}
代码写成这样我也是醉了!照这种写法就是一个一个处理请求好不?前一个没处理完就没法处理下一个,你这写的根本就不能说是个服务器。
就这样还和node.js拼了个55开,呵呵,真不知道作者到底是在黑.net还是在黑node.js
crossmix
crossmix

翻译不通顺,机器翻译有很多弊端,还是人翻译传神一些

sikele
sikele
C#的排序只需要改成Array.Sort(array, StringComparer.Ordinal)性能就远超nodejs了
sikele
sikele
我测试了一下,最大的性能瓶颈在排序上。。。 和IO没啥关系,替换了C#的排序算法后150次轻松达到了895,CPU:E3
sikele
sikele

引用来自“打杂程序猿”的评论

跟我 大node 比 io ..这不是找死吗...

在串行执行的情况下都能和nodejs打成这样子,不容易啊
sikele
sikele
原博主改完后的测试结果:
First I'm going to get the .NET performance numbers on my machine (Windows 7):

50 r// 1169 ms
100 r// 2214 ms
150 r// 3703 ms
And the original Node.js test on node 10.2:

50 r// 2973 ms
100 r// 6245 ms
150 r// 9548 ms
sikele
sikele
while (true)
{
var context = await this.listener.GetContextAsync();
this.ProcessRequest(context);
}
这种代码都写出来了,根本没法信服啊,没看出来在循环中阻塞了么,搞了半天就是单线程负载,不会用async await就别用,这里就直接Task.Run不就完了
sikele
sikele
C#都没异步彻底,async await是为了异步后回调回方法来用的,这可不算真的异步开了吧,while里面应该给每个请求开一个task,或者使用begin开异步和nodejs一样。nodejs异步后可没等待回调。
WilsonHuang
WilsonHuang
我只看了图和最后总结。说实话,脱离了业务场景的比较个人感觉意义都不大。net正常情况都是用IIS的,哪有自己去listen的,这反而不客观了
陈纪年
陈纪年
翻译太烂,看不下去。
返回顶部
顶部