記事の著者としてゴブワが書いたように (スペルは以下に保存されます):
これらのテストは、プログラマーの手に依存する「他のニュアンス」なしで、ベアサーバーの動作を示します。残念なことに、テストは同等ではなく、記事の客観性と結論に疑問を投げかけたコードは1行だけでした。
この記事には、元の記事からの多くのコピー&ペーストが含まれますが、それらが私を許してくれることを願っています。
テストの本質
テスト中、この設定ではすべての申請者がほぼ同じパフォーマンスで作業することが判明しました。すべてがV8のパフォーマンスに基づいています。 ただし、割り当ての実装は不要ではありませんでした-各言語の開発により、主観的な評価のかなりの部分を構成することが可能になり、最終的な選択に何らかの影響を与える可能性があります。したがって、2つのシナリオがあります。 1つ目は、ルートURLへの挨拶です。
GET / HTTP/1.1 Host: service.host HTTP/1.1 200 OK Hello World!
— , URL:
GET /greeting/user HTTP/1.1 Host: service.host HTTP/1.1 200 OK Hello, user
Node.js
var cluster = require('cluster'); var numCPUs = require('os').cpus().length; var http = require("http"); var debug = require("debug")("lite"); var workers = []; var server; cluster.on('fork', function(worker) { workers.push(worker); worker.on('online', function() { debug("worker %d is online!", worker.process.pid); }); worker.on('exit', function(code, signal) { debug("worker %d died", worker.process.pid); }); worker.on('error', function(err) { debug("worker %d error: %s", worker.process.pid, err); }); worker.on('disconnect', function() { workers.splice(workers.indexOf(worker), 1); debug("worker %d disconnected", worker.process.pid); }); }); if (cluster.isMaster) { debug("Starting pure node.js cluster"); ['SIGINT', 'SIGTERM'].forEach(function(signal) { process.on(signal, function() { debug("master got signal %s", signal); process.exit(1); }); }); for (var i = 0; i < numCPUs; i++) { cluster.fork(); } } else { server = http.createServer(); server.on('listening', function() { debug("Listening %o", server._connectionKey); }); var greetingRe = new RegExp("^\/greeting\/([a-z]+)$", "i"); server.on('request', function(req, res) { var match; switch (req.url) { case "/": { res.statusCode = 200; res.statusMessage = 'OK'; res.write("Hello World!"); break; } default: { match = greetingRe.exec(req.url); res.statusCode = 200; res.statusMessage = 'OK'; res.write("Hello, " + match[1]); } } res.end(); }); server.listen(8080, "127.0.0.1"); }
Go
package main import ( "fmt" "net/http" "regexp" ) func main() { reg := regexp.MustCompile("^/greeting/([a-z]+)$") http.ListenAndServe(":8080", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { switch r.URL.Path { case "/": fmt.Fprint(w, "Hello World!") default: fmt.Fprintf(w, "Hello, %s", reg.FindStringSubmatch(r.URL.Path)[1]) } })) }
Rust
extern crate hyper; extern crate regex; use std::io::Write; use regex::{Regex, Captures}; use hyper::Server; use hyper::server::{Request, Response}; use hyper::net::Fresh; use hyper::uri::RequestUri::{AbsolutePath}; fn handler(req: Request, res: Response<Fresh>) { let greeting_re = Regex::new(r"^/greeting/([a-z]+)$").unwrap(); match req.uri { AbsolutePath(ref path) => match (&req.method, &path[..]) { (&hyper::Get, "/") => { hello(&req, res); }, _ => { greet(&req, res, greeting_re.captures(path).unwrap()); } }, _ => { not_found(&req, res); } }; } fn hello(_: &Request, res: Response<Fresh>) { let mut r = res.start().unwrap(); r.write_all(b"Hello World!").unwrap(); r.end().unwrap(); } fn greet(_: &Request, res: Response<Fresh>, cap: Captures) { let mut r = res.start().unwrap(); r.write_all(format!("Hello, {}", cap.at(1).unwrap()).as_bytes()).unwrap(); r.end().unwrap(); } fn not_found(_: &Request, mut res: Response<Fresh>) { *res.status_mut() = hyper::NotFound; let mut r = res.start().unwrap(); r.write_all(b"Not Found\n").unwrap(); } fn main() { let _ = Server::http("127.0.0.1:8080").unwrap().handle(handler); }
Scala
package lite import akka.actor.{ActorSystem, Props} import akka.io.IO import spray.can.Http import akka.pattern.ask import akka.util.Timeout import scala.concurrent.duration._ import akka.actor.Actor import spray.routing._ import spray.http._ import MediaTypes._ import org.json4s.JsonAST._ object Boot extends App { implicit val system = ActorSystem("on-spray-can") val service = system.actorOf(Props[LiteActor], "demo-service") implicit val timeout = Timeout(5.seconds) IO(Http) ? Http.Bind(service, interface = "localhost", port = 8080) } class LiteActor extends Actor with LiteService { def actorRefFactory = context def receive = runRoute(route) } trait LiteService extends HttpService { val route = path("greeting" / Segment) { user => get { respondWithMediaType(`text/html`) { complete("Hello, " + user) } } } ~ path("") { get { respondWithMediaType(`text/html`) { complete("Hello World!") } } } }
, .
Don't click
, Node.js Go , Rust . Scala .
regex Rust:
regex Go:
? … , :
.
regex Rust:
Example: Avoid compiling the same regex in a loop
It is an anti-pattern to compile the same regular expression in a loop since compilation is typically expensive. (It takes anywhere from a few microseconds to a few milliseconds depending on the size of the regex.) Not only is compilation itself expensive, but this also prevents optimizations that reuse allocations internally to the matching engines.
In Rust, it can sometimes be a pain to pass regular expressions around if they're used from inside a helper function. Instead, we recommend using the lazy_static crate to ensure that regular expressions are compiled exactly once.
For example:
#[macro_use] extern crate lazy_static; extern crate regex; use regex::Regex; fn some_helper_function(text: &str) -> bool { lazy_static! { static ref RE: Regex = Regex::new("...").unwrap(); } RE.is_match(text) } fn main() {}
Specifically, in this example, the regex will be compiled when it is used for the first time. On subsequent uses, it will reuse the previous compilation.
regex Go:
But you should avoid the repeated compilation of a regular expression in a loop for performance reasons.
? … , :
! split , , regexp . wrk split.
.
Rust
extern crate hyper; extern crate regex; #[macro_use] extern crate lazy_static; use std::io::Write; use regex::{Regex, Captures}; use hyper::Server; use hyper::server::{Request, Response}; use hyper::net::Fresh; use hyper::uri::RequestUri::{AbsolutePath}; fn handler(req: Request, res: Response<Fresh>) { lazy_static! { static ref GREETING_RE: Regex = Regex::new(r"^/greeting/([a-z]+)$").unwrap(); } match req.uri { AbsolutePath(ref path) => match (&req.method, &path[..]) { (&hyper::Get, "/") => { hello(&req, res); }, _ => { greet(&req, res, GREETING_RE.captures(path).unwrap()); } }, _ => { not_found(&req, res); } }; } fn hello(_: &Request, res: Response<Fresh>) { let mut r = res.start().unwrap(); r.write_all(b"Hello World!").unwrap(); r.end().unwrap(); } fn greet(_: &Request, res: Response<Fresh>, cap: Captures) { let mut r = res.start().unwrap(); r.write_all(format!("Hello, {}", cap.at(1).unwrap()).as_bytes()).unwrap(); r.end().unwrap(); } fn not_found(_: &Request, mut res: Response<Fresh>) { *res.status_mut() = hyper::NotFound; let mut r = res.start().unwrap(); r.write_all(b"Not Found\n").unwrap(); } fn main() { let _ = Server::http("127.0.0.1:3000").unwrap().handle(handler); }
, .
, , . , , , , , , 2015.12.17 ( , ).
-
- Intel® Core(TM) i7-6820HQ CPU @ 2.70GHz, 4+4
- CPU Cache L1: 128 KB, L2: 1 MB, L3: 8 MB
- 8+8 GB 2133MHz DDR3
-
- Intel® Core(TM) i3 CPU 560 @ 3.33GHz, 2+2
- CPU Cache L1: 64 KB, L2: 4 MB
- 4+4 GB 1333MHz DDR3
- go 1.6.2, released 2016/04/20
- rust 1.5.0, released 2015/12/10. , Rust.
- , Scala Node.js, .
ab
50 000 10 , 256 .
ab -n50000 -c256 -t10 "http://127.0.0.1:3000/
Label | Time per request, ms | Request, #/sec |
---|---|---|
Rust | 11.729 | 21825.65 |
Go | 13.992 | 18296.71 |
ab -n50000 -c256 -t10 "http://127.0.0.1:3000/greeting/hello"
Label | Time per request, ms | Request, #/sec |
---|---|---|
Rust | 11.982 | 21365.36 |
Go | 14.589 | 17547.04 |
ab -n50000 -c256 -t10 "http://127.0.0.1:3000/"
Label | Time per request, ms | Request, #/sec |
---|---|---|
Rust | 8.987 | 28485.53 |
Go | 9.839 | 26020.16 |
ab -n50000 -c256 -t10 "http://127.0.0.1:3000/greeting/hello"
Label | Time per request, ms | Request, #/sec |
---|---|---|
Rust | 9.148 | 27984.13 |
Go | 9.689 | 26420.82 |
— , — . — - 500rps?! , , !
. , .
ab -n50000 -c256 -t10 "http://127.0.0.1:3000/"
Label | Time per request, ms | Request, #/sec |
---|---|---|
Rust | 5.601 | 45708.98 |
Go | 6.770 | 37815.62 |
ab -n50000 -c256 -t10 "http://127.0.0.1:3000/greeting/hello"
Label | Time per request, ms | Request, #/sec |
---|---|---|
Rust | 5.736 | 44627.28 |
Go | 6.451 | 39682.85 |
, Go, ?

, Mail.Ru Group . , 1.5 45 , Go , Mail.Ru Group, , , .
Rust , «The Computer Language Benchmarks Game» Rust vs Go 2015 2017 . .
, , Go, . Rust, , .
, , , .
Let the Holy War begin!