HTTP Server: Which code am I running?


#1

First post and first contact with Crystal. Hello!

Now a small question: which code am I actually running in the following example? Is 100% native Crystal, or is there some trick (like a C binding, or whatever)?

I just test this locally with Apache Benchmark (ab) to see how many “hello worlds” I get per second.

I’m asking because it’s blazingly fast, I cannot make a faster version in C, Rust or Go. It’s driving me nuts :smiley:

Cheers.

require “http/server”

module ServidorHttp
  VERSION = “0.1.0”
  server = HTTP::Server.new do |context|
    context.response.content_type = "text/plain"
    context.response.print "Hello, World!"
  end

  server.listen(8080)
end

#2

Welcome to Crystal! =)

HTTP::Server is completely implemented in Crystal. So yeah, Crystal is really fast. Mostly thanks to optimizations by LLVM though ;)

But I’m pretty you can get even more performance out of highly optimized C code. And it’s only a simple hello world, no real-world application.

Did you compile the crystal binary with --release? I’m pretty sure you did, because otherwise the other examples would be really crappy. HTTP::Server spawns a cheap fiber for every connection and can handle loads of concurrent requests on a single thread. I suppose the other implementations also execute concurrently?


#3

This is my favorite post in a while. :)
I have been trying to express this to other people and it is hard to get across.

The stdlib is written in a language I can reason about and enjoy writing and it is blazing fast.


#4

Well, I was trying to write these tiny HTTP servers with a comparable effort (and lines of code) so the Go and Rust versions just run whatever default HTTP server implementation they have (probably concurrent) and the C version is iterative because it’s annoying enough to handle the sockets, etc.

I didn’t want to test the coolest HTTP server library for C, which is probably quite good, but just plain C, which doesn’t have an HTTP server library. The “natural” way to get a concurrent server in plain C is arguably fork() which is probably overkill to return 13 bytes strings, and I was too lazy to use pthreads or select() or any of the other low-level tricks used by modern languages and libraries (async I/O, green threads, fibers, whatever)

Oh, and the simple hello world with no real world application (which is true) I believe it’s useful for this kind of benchmark since I get to compare the overhead added to “nothing” (just passing the string Hello World!") by each language / standard library. It turns out there is a difference! :smiley:

So far, I’m really happy with Crystal. I’ll try to do something useful with it ;)


#5

Of course, even such simple benchmarks have a value. It’s just that nobody should assume Crystal is always faster than any of the other ones.
I don’t know about Rust, but the Golang http server implementation should be relatively similar to Crystal’s. I don’t know why it’s less performant.
An C is obviously at a disadvantage if you don’t use at least roughly similar features as Crystal and Go employ. But it’s obviously fine if you don’t want to do the hassle with http libraries in C.