论 HTTP 性能，Go 与 .NET Core 一争雌雄
如前面所提的，我们会比较它们相同的东西，比如应用程序、预期响应及运行时的稳定性，所以我们不会把像对 JSON 或者 XML 的编码、解码这些烦多的事情加入比较游戏中来，仅仅只会使用简单的文本消息。为了公平起见，我们会分别使用 Go 和 .NET Core 的 MVC 架构模式。
Golang .NET
如前面所提的，我们会比较它们相同的东西，比如应用程序、预期响应及运行时的稳定性，所以我们不会把像对 JSON 或者 XML 的编码、解码这些烦多的事情加入比较游戏中来，仅仅只会使用简单的文本消息。为了公平起见，我们会分别使用 Go 和 .NET Core 的 MVC 架构模式。
![](/data/attachment/album/201710/06/111305ltswozo3cmicl3z6.png)


朋友们，你们好！


近来，我听到了大量的关于新出的 .NET Core 和其性能的讨论，尤其在 Web 服务方面的讨论更甚。


因为是新出的，我不想立马就比较两个不同的东西，所以我耐心等待，想等发布更稳定的版本后再进行。


本周一（8 月 14 日），微软[发布 .NET Core 2.0 版本](https://blogs.msdn.microsoft.com/dotnet/2017/08/14/announcing-net-core-2-0/)，因此，我准备开始。您们认为呢？


如前面所提的，我们会比较它们相同的东西，比如应用程序、预期响应及运行时的稳定性，所以我们不会把像对 JSON 或者 XML 的编码、解码这些烦多的事情加入比较游戏中来，仅仅只会使用简单的文本消息。为了公平起见，我们会分别使用 Go 和 .NET Core 的 [MVC 架构模式](https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller)。


### 参赛选手


[Go](https://golang.org/) （或称 Golang）： 是一种[快速增长](http://www.tiobe.com/tiobe-index/)的开源编程语言，旨在构建出简单、快捷和稳定可靠的应用软件。


用于支持 Go 语言的 MVC web 框架并不多，还好我们找到了 Iris ，可胜任此工作。


[Iris](http://iris-go.com/)： 支持 Go 语言的快速、简单和高效的微型 Web 框架。它为您的下一代网站、API 或分布式应用程序奠定了精美的表现方式和易于使用的基础。


[C#](https://en.wikipedia.org/wiki/C_Sharp_%28programming_language%29)： 是一种通用的、面向对象的编程语言。其开发团队由 [Anders Hejlsberg](https://twitter.com/ahejlsberg) 领导。


[.NET Core](https://www.microsoft.com/net/)： 跨平台，可以在极少时间内开发出高性能的应用程序。


可从 <https://golang.org/dl> 下载 Go ，从 <https://www.microsoft.com/net/core> 下载 .NET Core。


在下载和安装好这些软件后，还需要为 Go 安装 Iris。安装很简单，仅仅只需要打开终端，然后执行如下语句：



```
go get -u github.com/kataras/iris

```

### 基准


#### 硬件


* 处理器： Intel(R) Core(TM) i7–4710HQ CPU @ 2.50GHz 2.50GHz
* 内存： 8.00 GB


#### 软件


* 操作系统： 微软 Windows [10.0.15063 版本]， 电源计划设置为“高性能”
* HTTP 基准工具： <https://github.com/codesenberg/bombardier>， 使用最新的 1.1 版本。
* .NET Core： <https://www.microsoft.com/net/core>， 使用最新的 2.0 版本。
* Iris： <https://github.com/kataras/iris>， 使用基于 [Go 1.8.3](https://golang.org/) 构建的最新 8.3 版本。


两个应用程序都通过请求路径 “api/values/{id}” 返回文本“值”。


##### .NET Core MVC


![](/data/attachment/album/201710/06/111305kfvhsvvawf2o1sc5.png)


Logo 由 [Pablo Iglesias](https://github.com/campusMVP/dotnetCoreLogoPack) 设计。


可以使用 `dotnet new webapi` 命令创建项目，其 `webapi` 模板会为您生成代码，代码包含 `GET` 请求方法的 `返回“值”`。


源代码：



```
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;

namespace netcore_mvc
{
    public class Program
    {
        public static void Main(string[] args)
        {
            BuildWebHost(args).Run();
        }

        public static IWebHost BuildWebHost(string[] args) =>
            WebHost.CreateDefaultBuilder(args)
                .UseStartup<Startup>()
                .Build();
    }
}

```


```
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;

namespace netcore_mvc
{
    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddMvcCore();
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            app.UseMvc();
        }
    }
}

```


```
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;

namespace netcore_mvc.Controllers
{
    // ValuesController is the equivalent
    // `ValuesController` of the Iris 8.3 mvc application.
    [Route("api/[controller]")]
    public class ValuesController : Controller
    {
        // Get handles "GET" requests to "api/values/{id}".
        [HttpGet("{id}")]
        public string Get(int id)
        {
            return "value";
        }

        // Put handles "PUT" requests to "api/values/{id}".
        [HttpPut("{id}")]
        public void Put(int id, [FromBody]string value)
        {
        }

        // Delete handles "DELETE" requests to "api/values/{id}".
        [HttpDelete("{id}")]
        public void Delete(int id)
        {
        }
    }
}

```

运行 .NET Core web 服务项目：



```
$ cd netcore-mvc
$ dotnet run -c Release
Hosting environment: Production
Content root path: C:\mygopath\src\github.com\kataras\iris\_benchmarks\netcore-mvc
Now listening on: http://localhost:5000
Application started. Press Ctrl+C to shut down.

```

运行和定位 HTTP 基准工具：



```
$ bombardier -c 125 -n 5000000 http://localhost:5000/api/values/5
Bombarding http://localhost:5000/api/values/5 with 5000000 requests using 125 connections
 5000000 / 5000000 [=====================================================] 100.00% 2m3s
Done!
Statistics        Avg      Stdev        Max
  Reqs/sec     40226.03    8724.30     161919
  Latency        3.09ms     1.40ms   169.12ms
  HTTP codes:
    1xx - 0, 2xx - 5000000, 3xx - 0, 4xx - 0, 5xx - 0
    others - 0
  Throughput:     8.91MB/s

```

##### Iris MVC


![](/data/attachment/album/201710/06/111305gx85k8pcgchtz8gc.png)


Logo 由 [Santosh Anand](https://github.com/santoshanand) 设计。


源代码：



```
package main

import (
    "github.com/kataras/iris"
    "github.com/kataras/iris/_benchmarks/iris-mvc/controllers"
)

func main() {
    app := iris.New()
    app.Controller("/api/values/{id}", new(controllers.ValuesController))
    app.Run(iris.Addr(":5000"), iris.WithoutVersionChecker)
}

```


```
package controllers

import "github.com/kataras/iris/mvc"

// ValuesController is the equivalent
// `ValuesController` of the .net core 2.0 mvc application.
type ValuesController struct {
    mvc.Controller
}

// Get handles "GET" requests to "api/values/{id}".
func (vc *ValuesController) Get() {
    // id,_ := vc.Params.GetInt("id")
    vc.Ctx.WriteString("value")
}

// Put handles "PUT" requests to "api/values/{id}".
func (vc *ValuesController) Put() {}

// Delete handles "DELETE" requests to "api/values/{id}".
func (vc *ValuesController) Delete() {}

```

运行 Go web 服务项目：



```
$ cd iris-mvc
$ go run main.go
Now listening on: http://localhost:5000
Application started. Press CTRL+C to shut down.

```

运行和定位 HTTP 基准工具：



```
$ bombardier -c 125 -n 5000000 http://localhost:5000/api/values/5
Bombarding http://localhost:5000/api/values/5 with 5000000 requests using 125 connections
 5000000 / 5000000 [======================================================] 100.00% 47s
Done!
Statistics        Avg      Stdev        Max
  Reqs/sec    105643.81    7687.79     122564
  Latency        1.18ms   366.55us    22.01ms
  HTTP codes:
    1xx - 0, 2xx - 5000000, 3xx - 0, 4xx - 0, 5xx - 0
    others - 0
  Throughput:    19.65MB/s

```

想通过图片来理解的人，我也把我的屏幕截屏出来了！


请点击[这儿](https://github.com/kataras/iris/tree/master/_benchmarks/screens)可以看到这些屏幕快照。


#### 总结


* 完成 `5000000 个请求`的时间 - 越短越好。
* 请求次数/每秒 - 越大越好。
* 等待时间 — 越短越好。
* 吞吐量 — 越大越好。
* 内存使用 — 越小越好。
* LOC (代码行数) — 越少越好。


.NET Core MVC 应用程序，使用 86 行代码，运行 2 分钟 8 秒，每秒接纳 39311.56 个请求，平均 3.19ms 等待，最大时到 229.73ms，内存使用大约为 126MB（不包括 dotnet 框架）。


Iris MVC 应用程序，使用 27 行代码，运行 47 秒，每秒接纳 105643.71 个请求，平均 1.18ms 等待，最大时到 22.01ms，内存使用大约为 12MB。



> 
> 还有另外一个模板的基准，滚动到底部。
> 
> 
> 


**2017 年 8 月 20 号更新**


[Josh Clark](https://twitter.com/clarkis117) 和 [Scott Hanselman](https://twitter.com/shanselman)在此 [tweet 评论](https://twitter.com/shanselman/status/899005786826788865)上指出，.NET Core `Startup.cs` 文件中 `services.AddMvc();` 这行可以替换为 `services.AddMvcCore();`。我听从他们的意见，修改代码，重新运行基准，该文章的 .NET Core 应用程序的基准输出已经修改。


@topdawgevh @shanselman 他们也在使用 `AddMvc()` 而不是 `AddMvcCore()` ...，难道都不包含中间件？


 —  @clarkis117


@clarkis117 @topdawgevh Cool @MakisMaropoulos @ben*a*adams @davidfowl 我们来看看。认真学习下怎么使用更简单的性能默认值。


 —  @shanselman


@shanselman @clarkis117 @topdawgevh @ben*a*adams @davidfowl @shanselman @ben*a*adams @davidfowl 谢谢您们的反馈意见。我已经修改，更新了结果，没什么不同。对其它的建议，我非常欢迎。


 —  @MakisMaropoulos



> 
> 它有点稍微的不同但相差不大（从 8.61MB/s 到 8.91MB/s）
> 
> 
> 


想要了解跟 `services.AddMvc()` 标准比较结果的，可以点击[这儿](https://github.com/kataras/iris/blob/master/_benchmarks/screens/5m_requests_netcore-mvc.png)。


### 想再多了解点儿吗?


我们再制定一个基准，产生 `1000000 次请求`，这次会通过视图引擎由模板生成 `HTML` 页面。


#### .NET Core MVC 使用的模板



```
using System;

namespace netcore_mvc_templates.Models
{
    public class ErrorViewModel
    {
        public string Title { get; set; }
        public int Code { get; set; }
    }
}

```


```
 using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using netcore_mvc_templates.Models;

namespace netcore_mvc_templates.Controllers
{
    public class HomeController : Controller
    {
        public IActionResult Index()
        {
            return View();
        }

        public IActionResult About()
        {
            ViewData["Message"] = "Your application description page.";

            return View();
        }

        public IActionResult Contact()
        {
            ViewData["Message"] = "Your contact page.";

            return View();
        }

        public IActionResult Error()
        {
            return View(new ErrorViewModel { Title = "Error", Code = 500});
        }
    }
}

```


```
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;

namespace netcore_mvc_templates
{
    public class Program
    {
        public static void Main(string[] args)
        {
            BuildWebHost(args).Run();
        }

        public static IWebHost BuildWebHost(string[] args) =>
            WebHost.CreateDefaultBuilder(args)
                .UseStartup<Startup>()
                .Build();
    }
}

```


```
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;

namespace netcore_mvc_templates
{
    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            /*  An unhandled exception was thrown by the application.
                System.InvalidOperationException: No service for type
                'Microsoft.AspNetCore.Mvc.ViewFeatures.ITempDataDictionaryFactory' has been registered.
                Solution: Use AddMvc() instead of AddMvcCore() in Startup.cs and it will work.
            */
            // services.AddMvcCore();
            services.AddMvc();
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            app.UseStaticFiles();

            app.UseMvc(routes =>
            {
                routes.MapRoute(
                    name: "default",
                    template: "{controller=Home}/{action=Index}/{id?}");
            });
        }
    }
}

```


```
/*
wwwroot/css
wwwroot/images
wwwroot/js
wwwroot/lib
wwwroot/favicon.ico


Views/Shared/_Layout.cshtml
Views/Shared/Error.cshtml

Views/Home/About.cshtml
Views/Home/Contact.cshtml
Views/Home/Index.cshtml

These files are quite long to be shown in this article but you can view them at: 
https://github.com/kataras/iris/tree/master/_benchmarks/netcore-mvc-templates


```

运行 .NET Core 服务项目：



```
$ cd netcore-mvc-templates
$ dotnet run -c Release
Hosting environment: Production
Content root path: C:\mygopath\src\github.com\kataras\iris\_benchmarks\netcore-mvc-templates
Now listening on: http://localhost:5000
Application started. Press Ctrl+C to shut down.

```

运行 HTTP 基准工具：



```
Bombarding http://localhost:5000 with 1000000 requests using 125 connections
 1000000 / 1000000 [====================================================] 100.00% 1m20s
Done!
Statistics Avg Stdev Max
 Reqs/sec 11738.60 7741.36 125887
 Latency 10.10ms 22.10ms 1.97s
 HTTP codes:
 1xx — 0, 2xx — 1000000, 3xx — 0, 4xx — 0, 5xx — 0
 others — 0
 Throughput: 89.03MB/s

```

#### Iris MVC 使用的模板



```
package controllers

import "github.com/kataras/iris/mvc"

type AboutController struct{ mvc.Controller }

func (c *AboutController) Get() {
    c.Data["Title"] = "About"
    c.Data["Message"] = "Your application description page."
    c.Tmpl = "about.html"
}

```


```
package controllers

import "github.com/kataras/iris/mvc"

type ContactController struct{ mvc.Controller }

func (c *ContactController) Get() {
    c.Data["Title"] = "Contact"
    c.Data["Message"] = "Your contact page."
    c.Tmpl = "contact.html"
}

```


```
package models

// HTTPError a silly structure to keep our error page data.
type HTTPError struct {
    Title string
    Code  int
}

```


```
package controllers

import "github.com/kataras/iris/mvc"

type IndexController struct{ mvc.Controller }

func (c *IndexController) Get() {
    c.Data["Title"] = "Home Page"
    c.Tmpl = "index.html"
}

```


```
package main

import (
    "github.com/kataras/iris/_benchmarks/iris-mvc-templates/controllers"

    "github.com/kataras/iris"
    "github.com/kataras/iris/context"
)

const (
    // templatesDir is the exactly the same path that .NET Core is using for its templates,
    // in order to reduce the size in the repository.
    // Change the "C\\mygopath" to your own GOPATH.
    templatesDir = "C:\\mygopath\\src\\github.com\\kataras\\iris\\_benchmarks\\netcore-mvc-templates\\wwwroot"
)

func main() {
    app := iris.New()
    app.Configure(configure)

    app.Controller("/", new(controllers.IndexController))
    app.Controller("/about", new(controllers.AboutController))
    app.Controller("/contact", new(controllers.ContactController))

    app.Run(iris.Addr(":5000"), iris.WithoutVersionChecker)
}

func configure(app *iris.Application) {
    app.RegisterView(iris.HTML("./views", ".html").Layout("shared/layout.html"))
    app.StaticWeb("/public", templatesDir)
    app.OnAnyErrorCode(onError)
}

type err struct {
    Title string
    Code  int
}

func onError(ctx context.Context) {
    ctx.ViewData("", err{"Error", ctx.GetStatusCode()})
    ctx.View("shared/error.html")
}

```


```
/*
../netcore-mvc-templates/wwwroot/css
../netcore-mvc-templates/wwwroot/images
../netcore-mvc-templates/wwwroot/js
../netcore-mvc-templates/wwwroot/lib
../netcore-mvc-templates/wwwroot/favicon.ico
views/shared/layout.html
views/shared/error.html
views/about.html
views/contact.html
views/index.html
These files are quite long to be shown in this article but you can view them at: 
https://github.com/kataras/iris/tree/master/_benchmarks/iris-mvc-templates
*/


```

运行 Go 服务项目：



```
$ cd iris-mvc-templates
$ go run main.go
Now listening on: http://localhost:5000
Application started. Press CTRL+C to shut down.


```

运行 HTTP 基准工具：



```
Bombarding http://localhost:5000 with 1000000 requests using 125 connections
 1000000 / 1000000 [======================================================] 100.00% 37s
Done!
Statistics Avg Stdev Max
 Reqs/sec 26656.76 1944.73 31188
 Latency 4.69ms 1.20ms 22.52ms
 HTTP codes:
 1xx — 0, 2xx — 1000000, 3xx — 0, 4xx — 0, 5xx — 0
 others — 0
 Throughput: 192.51MB/s

```

#### 总结


* 完成 `1000000 个请求`的时间 - 越短越好。
* 请求次数/每秒 - 越大越好。
* 等待时间 — 越短越好。
* 内存使用 — 越小越好。
* 吞吐量 — 越大越好。


.NET Core MVC 模板应用程序，运行 1 分钟 20 秒，每秒接纳 11738.60 个请求，同时每秒生成 89.03M 页面，平均 10.10ms 等待，最大时到 1.97s，内存使用大约为 193MB（不包括 dotnet 框架）。


Iris MVC 模板应用程序，运行 37 秒，每秒接纳 26656.76 个请求，同时每秒生成 192.51M 页面，平均 1.18ms 等待，最大时到 22.52ms，内存使用大约为 17MB。


### 接下来呢？


[这里](https://github.com/kataras/iris/tree/master/_benchmarks)有上面所示的源代码，请下载下来，在您本地以同样的基准运行，然后把运行结果在这儿给大家分享。


想添加 Go 或 C# .net core WEB 服务框架到列表的朋友请向[这个仓库](https://github.com/kataras/iris)的 `_benchmarks` 目录推送 PR。


我也需要亲自感谢下 [dev.to](https://dev.to/kataras/go-vsnet-core-in-terms-of-http-performance) 团队，感谢把我的这篇文章分享到他们的 Twitter 账户。


感谢大家真心反馈，玩得开心！


#### 更新 : 2017 年 8 月 21 ，周一


很多人联系我，希望看到一个基于 .NET Core 的较低级别 Kestrel 的基准测试文章。


因此我完成了，请点击下面的[链接](https://medium.com/@kataras/iris-go-vs-net-core-kestrel-in-terms-of-http-performance-806195dc93d5)来了解 Kestrel 和 Iris 之间的性能差异，它还包含一个会话存储管理基准！




---


via: <https://hackernoon.com/go-vs-net-core-in-terms-of-http-performance-7535a61b67b8>


作者：[Gerasimos Maropoulos](https://hackernoon.com/@kataras?source=post_header_lockup) 译者：[runningwater](https://github.com/runningwater) 校对：[wxy](https://github.com/wxy)


本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux中国](https://linux.cn/) 荣誉推出

