Repository: costajob/app-servers
Branch: master
Commit: 38eebf5e632b
Files: 15
Total size: 10.3 KB
Directory structure:
gitextract_vcycwxna/
├── .gitignore
├── .ruby-version
├── README.md
└── servers/
├── .gitignore
├── crystal_server.cr
├── dart_server.dart
├── httpbeast_server.nim
├── node_server.js
├── plug_server/
│ ├── .gitignore
│ ├── lib/
│ │ ├── app.ex
│ │ └── server.ex
│ └── mix.exs
├── rack_server.ru
├── servemux_server.go
└── wsgi_server.py
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitignore
================================================
# Vagrant
.vagrant
# Elixir
/_build
/cover
/deps
erl_crash.dump
/servers/**/Gemfile.lock
*.ez
*.class
*.beam
# Python
/servers/__pycache__
/servers/*.pyc
/servers/.wsgi
# Crystal
*.dwarf
# Executable
crystal_server
fasthttp_server
httpbeast_server
*.aot*
================================================
FILE: .ruby-version
================================================
3.0.0
================================================
FILE: README.md
================================================
# Table of Contents
* [Scope](#scope)
* [Hello World](#hello-world)
* [Disclaimer](#disclaimer)
* [Languages](#languages)
* [Ruby](#ruby)
* [Python](#python)
* [JavaScript](#javascript)
* [Dart](#dart)
* [Elixir](#elixir)
* [Crystal](#crystal)
* [Nim](#nim)
* [GO](#go)
* [Tools](#tools)
* [Wrk](#wrk)
* [Platform](#platform)
* [RAM and CPU](#ram-and-cpu)
* [Benchmarks](#benchmarks)
* [Results](#results)
* [Puma](#puma)
* [Gunicorn with Meinheld](#gunicorn-with-meinheld)
* [Node Cluster](#node-cluster)
* [Dart HttpServer](#dart-httpserver)
* [Plug with Cowboy](#plug-with-cowboy)
* [Crystal HTTP](#crystal-http)
* [httpbeast](#httpbeast)
* [GO ServeMux](#go-servermux)
* [Hyper](#hyper)
## Scope
The idea behind this repository is to benchmark different languages implementation of HTTP server.
### Hello World
The *application* i tested is minimal: the HTTP version of the *Hello World* example.
This approach allows including languages i barely know, since it is pretty easy to find such implementation online.
If you're looking for more complex examples, you will have better luck with the [TechEmpower benchmarks](https://www.techempower.com/benchmarks/).
### Disclaimer
Please do take the following numbers with a grain of salt: it is not my intention to promote one language over another basing on micro-benchmarks.
Indeed you should never pick a language just basing on its presumed performance.
## Languages
I have became lazy with years and just adopt languages i can install via `homebrew`, sorry Oracle/MS. This also allows me to benchmark them in a single session, thus trying to use an environment as neutral as possible.
Where possible i just relied on the standard library, but when it is not production-ready (i.e. Ruby, Python).
### Ruby
[Ruby](https://www.ruby-lang.org/en/) 3.0.0 is used.
Ruby is a general-purpose, interpreted, dynamic programming language, focused on simplicity and productivity.
### Python
[Python](https://www.python.org/) 3.9.1 is used.
Python is a widely used high-level, general-purpose, interpreted, dynamic programming language.
### JavaScript
[Node.js](https://nodejs.org/en/) version 15.5.0 is used.
Node.js is based on the V8 JavaScript engine, optimized by Google and supporting most of the new language's features.
### Dart
[Dart](https://www.dartlang.org/) version 2.10.4 is used.
Dart is a VM based, object-oriented, sound typed language using a C-style syntax that transcompiles optionally into JavaScript.
### Elixir
[Elixir](http://elixir-lang.org/) 1.11.2 is used.
Elixir is a purely functional language that runs on the [Erlang](https://www.erlang.org/) VM and is strongly influenced by the Ruby syntax.
### Crystal
[Crystal](http://crystal-lang.org/) 0.35.1 is used.
Crystal has a syntax very close to Ruby, but brings some desirable features such as statically typing and ahead of time (AOT) compilation.
### Nim
[Nim](http://nim-lang.org/) 1.4.2 is used.
Nim is an AOT, Python inspired, statically typed language that comes with an ambitious compiler aimed to produce code in C, C++, JavaScript or ObjectiveC.
### GO
[GO](https://golang.org/) 1.15.6 is used.
GO is an AOT language that focuses on simplicity and offers a broad standard library with [CSP](https://en.wikipedia.org/wiki/Communicating_sequential_processes) constructs built in.
## Tools
### Wrk
I used [wrk](https://github.com/wg/wrk) as the loading tool.
I measured each application server six times, picking the best lap (but for VM based languages demanding longer warm-up).
```shell
wrk -t 4 -c 100 -d30s --timeout 2000 http://0.0.0.0:9292
```
### Platform
These benchmarks are recorded on a MacBook PRO 13 2019 having these specs:
* macOS Catalina
* 1.4 GHz Quad-Core Intel Core i5
* 8 GB 2133 MHz LPDDR3
### RAM and CPU
I measured RAM and CPU consumption by using macOS Activity Monitor dashboard and recording max consumption peak.
For the languages relying on pre-forking parallelism i reported the average consumption by taking a snapshot during the stress period.
## Benchmarks
### Results
| Language | App Server | Requests/sec | RAM (MB) | CPU (%) |
| :------------------------ | :------------------------------------------------ | ----------------: |---------: |--------: |
| [Ruby+MJIT](#ruby) | [Puma](#puma) | 36455.88 | > 100 | > 580 |
| [Elixir](#elixir) | [Plug with Cowboy](#plug-with-cowboy) | 46416.25 | 50.5 | 583.8 |
| [Ruby](#ruby) | [Puma](#puma) | 47975.36 | > 100 | > 580 |
| [Dart](#dart) | [Dart HttpServer](#dart-httpserver) | 59335.33 | 193.2 | 429.1 |
| [JavaScript](#javascript) | [Node Cluster](#node-cluster) | 87208.47 | > 200 | > 240 |
| [GO](#go) | [GO ServeMux](#go-servemux) | 103847.10 | 10.0 | 429.1 |
| [Python](#python) | [Gunicorn with Meinheld](#gunicorn-with-meinheld) | 120105.65 | > 40 | > 380 |
| [Nim](#nim) | [httpbeast](#httpbeast) | 128257.98 | 11.4 | 99.6 |
| [Crystal](#crystal) | [Crystal HTTP](#crystal-http) | 132699.78 | 8.5 | 246.7 |
### Puma
I tested Ruby by using a plain [Rack](http://rack.github.io/) application served by [Puma](http://puma.io).
#### Bootstrap
```shell
RUBYOPT='--jit' puma -w 8 -t 2 --preload servers/rack_server.ru
```
### Gunicorn with Meinheld
I tested Python by using [Gunicorn](http://gunicorn.org/) spawning [Meinheld](http://meinheld.org/) workers with a plain WSGI compliant server.
#### Bootstrap
```shell
cd servers
gunicorn -w 4 -k meinheld.gmeinheld.MeinheldWorker -b :9292 wsgi_server:app
```
### Node Cluster
I used the cluster module included into Node's standard library.
#### Bootstrap
```shell
node servers/node_server.js
```
### Dart HttpServer
I used the async HTTP server embedded into the Dart standard library and compiled it with `dart2native` AOT compiler.
#### Bootstrap
```shell
dart2native servers/dart_server.dart -k aot
dartaotruntime servers/dart_server.aot
```
### Plug with Cowboy
I tested Elixir by using [Plug](https://github.com/elixir-lang/plug) library that provides a [Cowboy](https://github.com/ninenines/cowboy) adapter.
#### Bootstrap
```shell
cd servers/plug_server
MIX_ENV=prod mix compile
MIX_ENV=prod mix run --no-halt
```
### Crystal HTTP
I used Crystal HTTP server standard library, enabling parallelism by using the `preview_mt` flag.
#### Bootstrap
```shell
crystal build -Dpreview_mt --release servers/crystal_server.cr
./crystal_server
```
### httpbeast
To test Nim i opted for the [httpbeast](https://github.com/dom96/httpbeast) library: an asynchronous server relying on Nim HTTP standard library.
#### Bootstrap
```shell
nim c -d:release --threads:on servers/httpbeast_server.nim
./servers/httpbeast_server
```
### GO ServeMux
I used the [HTTP ServeMux](https://golang.org/pkg/net/http/) GO standard library.
#### Bootstrap
```shell
go run servers/servemux_server.go
```
================================================
FILE: servers/.gitignore
================================================
__pycache__
nimcache
go_server
crystal_server
nim_server
pony_server
================================================
FILE: servers/crystal_server.cr
================================================
require "http/server"
server = HTTP::Server.new do |context|
context.response.content_type = "text/plain"
context.response.print "Hello World"
end
server.listen(9292)
================================================
FILE: servers/dart_server.dart
================================================
import 'dart:async';
import 'dart:io';
import 'dart:isolate';
const String _HOST = '0.0.0.0';
const String _GREET = 'Hello World';
_startServer(arg) async {
var server = await HttpServer.bind(_HOST, 9292, shared: true);
await for (HttpRequest request in server) {
request.response
..write(_GREET)
..close();
}
}
void main() {
final cpus = Platform.numberOfProcessors;
for (int i = 0; i < cpus; i++)
Isolate.spawn(_startServer, null);
_startServer(null);
}
================================================
FILE: servers/httpbeast_server.nim
================================================
import asyncdispatch, httpbeast, options
const settings = httpbeast.initSettings(Port(9292))
proc onRequest(req: Request): Future[void] =
if req.httpMethod == some(HttpGet):
const data = "Hello World"
const headers = "Content-Type: text/plain"
req.send(Http200, data, headers)
run(onRequest, settings)
================================================
FILE: servers/node_server.js
================================================
const cluster = require('cluster');
const http = require('http');
const numCPUs = require('os').cpus().length;
if (cluster.isMaster) {
for (let i = 0; i < numCPUs; i++) {
cluster.fork();
}
} else {
http.createServer((req, res) => {
res.writeHead(200);
res.end('Hello World');
}).listen(9292);
}
================================================
FILE: servers/plug_server/.gitignore
================================================
/_build
/cover
/deps
erl_crash.dump
*.ez
./*.beam
mix.lock
================================================
FILE: servers/plug_server/lib/app.ex
================================================
defmodule App do
use Application
def start(_type, _args) do
children = [
Plug.Cowboy.child_spec(scheme: :http, plug: Server, options: [port: 9292])
]
opts = [strategy: :one_for_one, name: App.Supervisor]
Supervisor.start_link(children, opts)
end
end
================================================
FILE: servers/plug_server/lib/server.ex
================================================
defmodule Server do
import Plug.Conn
def init(opts), do: opts
def call(conn, _opts) do
conn
|> put_resp_content_type("text/plain")
|> send_resp(200, "Hello world")
end
end
================================================
FILE: servers/plug_server/mix.exs
================================================
defmodule PlugServer.Mixfile do
use Mix.Project
def project do
[app: :server,
version: "1.2.0",
elixir: "~> 1.8",
start_permanent: Mix.env == :prod,
deps: deps()]
end
def application do
[applications: [:cowboy, :plug],
mod: {App, []},
env: [cowboy_port: 9292]]
end
defp deps do
[{:cowboy, "~> 2.6.3"},
{:plug, "~> 1.8"},
{:plug_cowboy, "~> 2.0.2"}]
end
end
================================================
FILE: servers/rack_server.ru
================================================
run Proc.new { |env| ['200', {'Content-Type' => 'text/plain'}, ['Hello World']] }
================================================
FILE: servers/servemux_server.go
================================================
package main
import (
"fmt"
"log"
"net/http"
)
func main() {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, "Hello World")
})
log.Fatal(http.ListenAndServe("0.0.0.0:9292", nil))
}
================================================
FILE: servers/wsgi_server.py
================================================
BODY = b'Hello World'
LEN = str(len(BODY))
def app(_, resp):
body = BODY
resp('200 OK', [('Content-Type', 'text/plain'), ('Content-Length', LEN)])
yield body
gitextract_vcycwxna/
├── .gitignore
├── .ruby-version
├── README.md
└── servers/
├── .gitignore
├── crystal_server.cr
├── dart_server.dart
├── httpbeast_server.nim
├── node_server.js
├── plug_server/
│ ├── .gitignore
│ ├── lib/
│ │ ├── app.ex
│ │ └── server.ex
│ └── mix.exs
├── rack_server.ru
├── servemux_server.go
└── wsgi_server.py
SYMBOL INDEX (13 symbols across 6 files)
FILE: servers/dart_server.dart
function _startServer (line 8) | _startServer(arg)
function main (line 17) | void main()
FILE: servers/plug_server/lib/app.ex
class App (line 1) | defmodule App
method start (line 4) | def start(_type, _args) do
FILE: servers/plug_server/lib/server.ex
class Server (line 1) | defmodule Server
method init (line 4) | def init(opts), do: opts
method call (line 6) | def call(conn, _opts) do
FILE: servers/plug_server/mix.exs
class PlugServer.Mixfile (line 1) | defmodule PlugServer.Mixfile
method project (line 4) | def project do
method application (line 12) | def application do
method deps (line 18) | defp deps do
FILE: servers/servemux_server.go
function main (line 9) | func main() {
FILE: servers/wsgi_server.py
function app (line 5) | def app(_, resp):
Condensed preview — 15 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (12K chars).
[
{
"path": ".gitignore",
"chars": 259,
"preview": "# Vagrant\n.vagrant\n\n# Elixir\n/_build\n/cover\n/deps\nerl_crash.dump\n/servers/**/Gemfile.lock\n*.ez\n*.class\n*.beam\n\n# Python\n"
},
{
"path": ".ruby-version",
"chars": 6,
"preview": "3.0.0\n"
},
{
"path": "README.md",
"chars": 7431,
"preview": "# Table of Contents\n\n* [Scope](#scope)\n * [Hello World](#hello-world)\n * [Disclaimer](#disclaimer)\n* [Languages](#lang"
},
{
"path": "servers/.gitignore",
"chars": 69,
"preview": "__pycache__\nnimcache\ngo_server\ncrystal_server\nnim_server\npony_server\n"
},
{
"path": "servers/crystal_server.cr",
"chars": 173,
"preview": "require \"http/server\"\n\nserver = HTTP::Server.new do |context|\n context.response.content_type = \"text/plain\"\n context.r"
},
{
"path": "servers/dart_server.dart",
"chars": 491,
"preview": "import 'dart:async';\nimport 'dart:io';\nimport 'dart:isolate';\n\nconst String _HOST = '0.0.0.0';\nconst String _GREET = 'He"
},
{
"path": "servers/httpbeast_server.nim",
"chars": 325,
"preview": "import asyncdispatch, httpbeast, options\n\nconst settings = httpbeast.initSettings(Port(9292))\n\nproc onRequest(req: Reque"
},
{
"path": "servers/node_server.js",
"chars": 316,
"preview": "const cluster = require('cluster');\nconst http = require('http');\nconst numCPUs = require('os').cpus().length;\n\nif (clus"
},
{
"path": "servers/plug_server/.gitignore",
"chars": 59,
"preview": "/_build\n/cover\n/deps\nerl_crash.dump\n*.ez\n./*.beam\nmix.lock\n"
},
{
"path": "servers/plug_server/lib/app.ex",
"chars": 280,
"preview": "defmodule App do\n use Application\n\n def start(_type, _args) do\n children = [\n Plug.Cowboy.child_spec(scheme: :"
},
{
"path": "servers/plug_server/lib/server.ex",
"chars": 194,
"preview": "defmodule Server do\n import Plug.Conn\n\n def init(opts), do: opts\n\n def call(conn, _opts) do\n conn\n |> put_resp_"
},
{
"path": "servers/plug_server/mix.exs",
"chars": 423,
"preview": "defmodule PlugServer.Mixfile do\n use Mix.Project\n\n def project do\n [app: :server,\n version: \"1.2.0\",\n elixi"
},
{
"path": "servers/rack_server.ru",
"chars": 82,
"preview": "run Proc.new { |env| ['200', {'Content-Type' => 'text/plain'}, ['Hello World']] }\n"
},
{
"path": "servers/servemux_server.go",
"chars": 238,
"preview": "package main\t\n\n import (\t\n\t\"fmt\"\t\n\t\"log\"\t\n\t\"net/http\"\t\n)\t\n\n func main() {\t\n\thttp.HandleFunc(\"/\", func(w http.ResponseWri"
},
{
"path": "servers/wsgi_server.py",
"chars": 172,
"preview": "BODY = b'Hello World'\nLEN = str(len(BODY))\n\n\ndef app(_, resp):\n body = BODY\n resp('200 OK', [('Content-Type', 'tex"
}
]
About this extraction
This page contains the full source code of the costajob/app-servers GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 15 files (10.3 KB), approximately 3.4k tokens, and a symbol index with 13 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.