Go vs .NET Core in terms of HTTP performance
Tags: benchmark, net, go, webdev
Published: 2017-08-19 05:22:31

---
title: Go vs .NET Core in terms of HTTP performance
published: true
description: A Fair benchmark between .NET Core and Go 
tags: benchmark, .net, go, webdev
---

![article cover](https://cdn-images-1.medium.com/max/938/1*60T60jSMO5yxUqJQmLZa4A.png)


Hello Friends!

Lately I’ve heard a lot of discussion around the newÂ .NET Core and its performance especially on web servers.

I didn’t want to start comparing two different things, so I did patience for quite long for a more stable version.

However, this Monday, [Microsoft announced theÂ .NET Core version 2.0](https://blogs.msdn.microsoft.com/dotnet/2017/08/14/announcing-net-core-2-0/), so I feel ready to do it! Do you?

----


As we already mentioned, we will compare two identical things here, in terms of application, the expected response and the stability of their run times, so we will not try to put more things in the game like `JSON` or `XML` encoders and decoders, just a simple text message. To achieve a fair comparison we will use the [MVC architecture pattern](https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller) on both sides, Go andÂ .NET Core.


## Prerequisites

[Go](https://golang.org) (or Golang): is a [rapidly growing](http://www.tiobe.com/tiobe-index/) open source programming language designed for building simple, fast, and reliable software.

There are not lot of web frameworks for Go with MVC support but, luckily for us Iris does the job.

[Iris](https://github.com/kataras/iris): A fast, simple and efficient micro web framework for Go. It provides a beautifully expressive and easy to use foundation for your next website, API, or distributed app.

[C#](https://en.wikipedia.org/wiki/C_Sharp_%28programming_language%29): is a general-purpose, object-oriented programming language. Its development team is led by [Anders Hejlsberg](https://twitter.com/ahejlsberg).

[.NET Core](https://www.microsoft.com/net/): Develop high performance applications in less time, on any platform.

Download Go from https://golang.org/dl and .NET Core from https://www.microsoft.com/net/core.

After you've download and install these, you will need Iris from Go’s side.  Installation is very easy, just open your terminal and execute:

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

# Benchmarking

#### Hardware

* Processor: Intel(R) Core(TM) **i7–4710HQ** CPU @ 2.50GHz 2.50GHz
* RAM: **8.00 GB**

#### Software

* OS: Microsoft **Windows** [Version **10**.0.15063], power plan is "High performance"
* HTTP Benchmark Tool: https://github.com/codesenberg/bombardier, latest version **1.1**
* **.NET Core**: https://www.microsoft.com/net/core, latest version **2.0**
* **Iris**: https://github.com/kataras/iris, latest version **8.3** built with [go1.8.3](https://golang.org)

Both of the applications will just return the text “value” on request path “api/values/{id}”.

### .NET Core MVC

![Logo designed by Pablo Iglesias](https://cdn-images-1.medium.com/max/1250/1*v2VJL3-I3bLyuehntuqfng.png)

Created using `dotnet new webapi` . That `webapi` template will generate the code for you, including the `return “value”` on `GET` method requests.

Source Code


**Program.cs**

```csharp
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();
    }
}

```
**Startup.cs**

```csharp
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();
        }
    }
}

```

The actual **Controllers/ValuesController.cs**

```csharp
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)
        {
        }
    }
}

```


_Start theÂ .NET Core web server and run the benchmark tool_


```
$ 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..
```

```
$ 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

![Logo designed by SantoshÂ Anand](https://cdn-images-1.medium.com/max/1250/1*zf4BjL-7MQNJGikw5E-iNA.png)

Source Code


**main.go**

```go
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"))
}
```

**controllers/values_controller.go**

```go
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() {}

```


_Start theÂ Go web server and run the benchmark tool_


```
$ cd iris-mvc
$ go run main.go
Now listening on: http://localhost:5000
Application started. Press CTRL+C to shut down.
```
```
$ 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
```

For those who understand better by images, I did print my screen too!

Click [here](https://github.com/kataras/iris/tree/master/_benchmarks/screens) to see these screenshots.

### Summary

* Time to complete the `5000000 requests` - smaller is better.
* Reqs/secâ€Š–â€Šbigger is better.
* Latencyâ€Š–â€Šsmaller is better
* Throughputâ€Š–â€Šbigger is better.
* Memory usageâ€Š–â€Šsmaller is better.
* LOC (Lines Of Code)â€Š–â€Šsmaller is better.

.NET Core MVC Application, written using 86 lines of code, ran for **2 minutes and 8 seconds** serving **39311.56** requests per second within **3.19ms** latency in average and **229.73ms max**, the memory usage of all these was ~126MB (without the dotnet host).

Iris MVC Application, written using 27 lines of code, ran for **47 seconds** serving **105643.71** requests per second within **1.18ms** latency in average and **22.01ms max**, the memory usage of all these was ~12MB.


> There is also another benchmark with templates, scroll to the bottom.


**Update: 20 August 2017**

As [Josh Clark](https://twitter.com/clarkis117) and [Scott Hanselman”](https://twitter.com/shanselman)” pointed out [on this status](https://twitter.com/shanselman/status/899005786826788865), on .NET Core `Startup.cs` file the line with `services.AddMvc();` can be replaced with `services.AddMvcCore();`. I followed their helpful instructions and re-run the benchmarks. The article now contains the latest benchmark output for the .NET Core application with the change both Josh and Scott noted.

The twitter conversion: https://twitter.com/MakisMaropoulos/status/899113215895982080

For those who want to compare with the standard `services.AddMvc();` you can see the old output by pressing [here](https://github.com/kataras/iris/blob/master/_benchmarks/screens/5m_requests_netcore-mvc.png).


## Can you stay a bit longer for one more?

Let’s run one more benchmark, `spawn 1000000 requests` but this time we expect `HTML` generated by templates via the view engine.


### .NET Core MVC with Templates

Source code files for this test are quite long to be shown in this article, however you can review them at: https://github.com/kataras/iris/tree/master/_benchmarks/netcore-mvc-templates


_Start theÂ .NET Core web server and run the benchmark tool_


```
$ 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.
```

```
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 with Templates

Source code files for this test are quite long to be shown in this article, however you can review them at: https://github.com/kataras/iris/tree/master/_benchmarks/iris-mvc-templates


_Start theÂ Go web server and run the benchmark tool_

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

```
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
```

#### Summary

* Time to complete the `1000000 requests` - smaller is better.
* Reqs/sec - bigger is better.
* Latency - smaller is better
* Memory usage - smaller is better.
* Throughput - bigger is better.

.NET Core MVC with Templates Application ran for **1 minute and 20 seconds** serving **11738.60** requests per second with **89.03MB/s** within **10.10ms** latency in average and **1.97s** max, the memory usage of all these was ~193MB (without the dotnet host).

Iris MVC with Templates Application ran for **37 seconds** serving **26656.76** requests per second with **192.51MB/s** within **1.18ms** latency in average and **22.52ms** max, the memory usage of all these was ~17MB.


# What next?

Download the example source code from [there](https://github.com/kataras/iris/tree/master/_benchmarks) and run the same benchmarks from your machine, then come back here and share your results with the rest of us!


**Thank you all** for the 100% green feedback. 

P.S

I'm trying to respond to all of you but please do me a huge favor and check if your question is already answered on somewhere else's question first, thank you and have fun!

### Update: Monday, 21 August 2017

A lot of people reached me saying that want to see a new benchmarking article based on the .NET Core’s "lower level" **Kestrel** this time.
So I did, follow the below link to learn the performance difference between Kestrel and Iris, it contains a sessions storage management benchmark too!

https://medium.com/@kataras/iris-go-vs-net-core-kestrel-in-terms-of-http-performance-806195dc93d5


-----

_This article was originally posted at [medium](https://medium.com/@kataras/go-vs-net-core-in-terms-of-http-performance-7535a61b67b8)_