I would love to see someone take a deep dive into why their Phoenix thing is "so much faster" than with Rails. I mean really look at the whole stack from the VM, to different pieces of the framework like views and DB interaction. Erlang definitely does concurrency well, but it is not that much faster than Ruby in terms of "raw speed". I'd be fascinated to see someone actually do the work and look at where Phoenix is eking out those gains.
Some bigger details why phoenix is so fast despite erlang being a "slow" language:
- macros: fancy syntax and "magic" can be resolved at compile-time. Less work to do on runtime.
- templates: they get handled at compile-time, too, resulting in functions with blobs of binaries. This matters a lot, since a specific template-binary exists only once throughout the application and gets re-used whenever needed. This way you get near instant templating, instead of the usual string processing on every request.
- dispatching code like the routing that must be done on every request is like rails a DSL, but actually a macro, that gets compiled down to basic pattern matches, which is extremely fast.
- the concurrency model is extremely lightweight, handling more requests and/or doing more stuff per request is much more efficient hardware-wise. Indirect performance gain.
Just a few points that have a very noticeably impact, there are probably more. It boils down to the erlang vm's concurrency and pattern matching performance, plus elixir's compile-time macros and the fact that they treat strings as immutable binaries.
All well and good, but Erlang/beam code is not that fast.
> templates
Ruby's templates are parsed into code that stays in memory, too, so it's not like they're re-parsed each and every time.
> routing
Perhaps clever use of pattern matching helps here. But my point is: someone should dissect these things in a real-world-ish application to see what's actually true.
> concurrency
Yes, but let's be precise. Everyone knows Erlang's concurrency is way better than Ruby's. The claim was 'fast' though. As well as maintainable, which seems curious given that there are no really old Phoenix apps out there.
True, no doubt. You wanted a comparison why phoenix is faster than rails. And simply doing things at compile time reduces work at runtime. In Ruby, all Metaprogramming must be done at runtime, for example via method_missing trickery (been there, done that).
> Ruby's templates are parsed into code that stays in memory, too, so it's not like they're re-parsed each and every time.
This is actually not the same. A single immutable blob of binary (elixir strings) which is shared throughout the whole application can leverage hardware caching better. Jose could answer this probably better than I can do.
> someone should dissect these things in a real-world-ish application to see what's actually true.
Well at least I know that BEAM processes are far lighter than eg: goroutines. Also there is a per-process GC, so no "stop the world", much smaller units for individual collects, and when a process finishes before the heap grows full, it can be discarded directly.
> maintainable, which seems curious given that there are no really old Phoenix apps out there
Fair enough.
Personally I'd not wait until a software stack is a decade old before even considering it. I have at least worked on Elixir/Phoenix projects for many months now on-off with multiple colleagues, and it was/is still pure joy. Aesthetically pleasing syntax helps (broken window syndrome I guess), plus functional programming style in general, plus phoenix' foundation in "plug" and the clear modularity. "Let it crash" with supervisors also is incredibly robust, and robustness in itself leads to less maintenance costs.
All good points. As I keep saying, I'm an Erlang fan. I actually used it at my last job, and have used it on and off since 2004-ish. It definitely has some advantages, but I'm just curious where it's actually beating Rails, and with what kinds of workloads and test methodology and so on.
Stuff like "Erlang processes are lighter" matters in some contexts, but not in a straight up speed contest. It matters a lot when you start trying to handle a bunch of concurrent connections, so maybe that's where we're getting some of the claims from.
I'd say you really should have a look into https://www.youtube.com/watch?v=OxhTQdcieQE . A really great presentation, including numbers and real world backup data, plus conceptual overviews.
It sounds like you're undervaluing concurrency. Concurrency is huge for a web application. If you were say doing image manipulation or other DSP where you needed "raw speed" you'd want to choose a language like C, Go, Rust. But in a web application you're handling hundreds, thousands, to millions of requests per second; concurrency is crucial for that kind of throughput. A developer on my team did some quick benchmarks and found that that Phoenix gives an order of magnitude better performance than Rails. Thats not negligible.
I was a bit surprised by its performance in the last TechEmpower benchmarks: roughly equivalent to Rails and other Ruby-based solutions (PHP, too).
It could be a case of not yet being optimized for the tests, but I was expecting much more impressive numbers out of the box (particularly after the full-court press on the boards and blogs).
The Phoenix tests had a ton of errors and there was no preview run so whoever submitted them wasn't able to fix them. This has happened with a bunch of different languages/frameworks in the past and until the errors in the implementation are sorted out the benchmarks are basically meaningless.
From what I've read in the comments so far, you won't see it thinking in terms of speed of Erlang vs Ruby. It sounds like the gains come from baked in behavior, so that "Rails + Redis" or "Rails + Redis + nginx" is equivalent to Phoenix alone. I'm still only reading about this, though. No Elixir experience here.
Erlang definitely does a lot out of the box without needing to rely on other systems and that's a great thing, but we're hearing claims about "fast" and "more maintainable" and I'd like to see more details.
I used Erlang at the last place I worked and like it a lot, but Rails is pretty good too in my book.
For me, it's "fast" meaning developer time. A typical first pass at a Rails view might be 300ms vs. 300 micro secs in Phoenix. This extra headroom represents hours of optimization I don't need to do, in order to stay under 200ms per request.
The one thing that comes to mind is that since each process has its own isolated memory space, Erlang's GC is not a "stop the universe" kind of thing, the GC can run in parallel with other processes.
(edit: again, this is just intuition on my part, I haven't remotely done the deep dive you're talking about)