5 ms·
Can we stop with the erlang/Elixir is slow? For most web services it is as fast as go. For my last side project I was evaluating go and erlang. Just to test ou
by noncoml 9y ago
Can we stop with the erlang/Elixir is slow? For most web services it is as fast as go.
For my last side project I was evaluating go and erlang. Just to test out how faster go is, I quickly coded a simple HTTP request in both language(I am not an expert in either).
The server would get a request with large body, cache it to a file on the disk, then load it in 128k chunks, get the hash of the chunk and save both the digest and the 128k data to a database.
To my surprise, erlang was consistently slightly faster for each request. Happy to share the code snips of both if anyone want to audit/scrutinize.
Edit: Code for both: https://pastebin.com/aBQWqkG3 https://pastebin.com/aBQWqkG3
On my laptop a single request(1.2MB) takes around 230ms for Erlang and 280ms for Go. Not a scientific test, but it gives an idea.
- lobster_johnson 9y agoYour Go code uses "defer" in a for loop, which could be a performance bottleneck. The deferred function call doesn't run until the saveToDb function returns. A simple fix would be to reuse the rows variable and put the defer outside the loop. I believe it might, depending on the database driver, also cause another issue. Since you're not closing the rows right away, and not even consuming the rows, this may force the driver to mark the internal connection as busy until the defer runs, meaning the next database call would have to open a new connection. Try closing the rows as soon as you can. If you don't expect any results, you can also use Exec instead. Then there's nothing to close.
- noncoml 9y agoI keep the habit of deferring immediately so I don’t forget later if the fucnction gets long. But I see what you mean, on this case, inside the loop, is really bad idea. Will try with Exec and without the defer and see if it makes a noticeable difference. The driver is the MySQL one for what’s worth it. Postgres was a bit slower.
- noncoml 9y agoJust to update that you where right. Without the `defer` now golang is as fast as erlang. Exec vs Query didn't make a difference. Yet another update: things get really interesting when I run wrk. I don’t want to spoil it for you. I can let you try it ;)
- egisspegis 9y agoPlease spoil it for us. I would love to see results, but can't run wrk myself at the moment.
- kjksf 9y agoThe difference is that in Go sha256.Sum256() is implemented in Go and I'm pretty sure in Erlang crypto::hash() is implemented in C. The program is mostly i/o with sha256 being the only CPU intensive part. If sha256 (or any compute-intensive part) was implemented in Erlang, it would be at least 10x slower than Go version. Go version probably has a bug: file.Read() doesn't guarantee to fill the buffer, you need to use io.ReadFull() for that. Both versions unnecessarily write a copy of the file to disk (and don't seem to delete those randomly-named files from disk). In Go saveToDb() would take io.Reader as an argument and you would pass r.Body directly. Go is much faster than Erlang, it just doesn't show up in every toy program.
- noncoml 9y agoDid you miss the: “For most web services it is as fast as go.”? I think the request in my test is quite representative of what an actual web server will be like: mostly IO. As a general programming language, go is much faster, I completely agree with you. Btw: I don’t think deleting the files would make a difference. Also I save the body to file first because with cowboy I had trouble splitting it to the exact chick sizes. Will try without it in go and update.
- noncoml 9y agoJust to update that getting rid of the part of saving to the disk first, and getting rid of the defer as another person suggested, the number now are around 200ms for golang and 210 for erlang. IMHO it is not as huge as everybody makes it look like. Again, as you very correctly pointed out, this is of course only for IO intensive applications.
- microcolonel 9y agoElixir is slow enough to get in the way, if we're talking about complex processing tasks. I (along with a team) was tasked with writing a fairly complex accounting/numerics application in Elixir, and one day I had to basically call the whole thing a thousand times more often per request. It took me weeks to accumulate enough microoptimizations to make the thing function (because it was already reasonably well designed). It's a sort of a "it's fast enough until it isn't" type thing. Python is fast in the same way (and faster with each release!). For anything that isn't dominated by network and database time, language and runtime performance matters, and OTP/Elixir is slow in that way. In terms of "real world performance", it can sometimes matter more that the incremental cost of preempting your beam process is low, more than whether your process completes in more or less time.
- noncoml 9y agoCompletely agree. What saddens me is that only Erlang/Elixir get the “it’s slow” argument although they are in the same class as python and ruby.
- dahauns 9y agoI know what you mean. I don't know how often I've read "I prefer python/ruby/etc. because its not as bloated and slow as Java"...sigh
- kenhwang 9y agoWe did this experiment too! When we did our initial benchmarks, Go had a healthy performance lead on pure CPU or IO workloads over Elixir and Scala. Then we went through with the full POC of our toy webserver project and the performance difference between Go, Elixir, and Scala was pretty much insignificant (within 5% of each other).