fireproofsocks
I’ve been working on an Elixir project that has required a lot of scripting. I usually reach for Elixir because I like it more (and in this case, I could reuse code). However, I’ve noticed that the performance is sometimes poor. I have tried doing the same task in Python, and at in my initial tests, Python is much faster.
Here’s the repo (specifically the scripts/ directory):
https://github.com/fireproofsocks/ex_vs_py
To reproduce the behavior (after install and mix deps.get):
mix run scripts/make_files.exs: this preps the directory with sample files – takes maybe 30 seconds.mix run scripts/vet_files.exsto run the Elixir version of parsing/vetting the files. Example output:Duration: 2424 ms- Compare with
python scripts/vet_files.pywith example outputDuration: 608 ms
I haven’t spent a whole lot of time trying to refactor the Elixir (or the Python) code, but this setup is a fairly accurate recreation of one of the tasks we needed to figure out, and when you’re dealing with lots and lots of files, even little inefficiencies add up.
I’m wondering if the community here can share any insights or knowledge about Elixir’s performance for scripts such as this. Thanks in advance!
Trending in Discussions
Other Trending Topics
Chat & Discussions>Discussions
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #channels
- #elixirconf
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #blog-post
- #phoenix_html
- #ai
- #iex
- #graphql
- #genstage
- #elixirconf-us
- #websockets
- #supervisor
- #advent-of-code
- #distillery
- #processes
- #api
- #forms
- #hex
- #security
- #metaprogramming











Showing Posts 1 to 10- Show Best Posts
- Show All (oldest first)
- Show All (newest first)
BradS2S
I’d be curious what would happen if you piped the file into file.read instead of stream. It looks like Python reads the file completely into memory before processing the lines.
Also you might want to check out genstage which is optimized for creating data pipelines.
*disclaimer: I’m less experienced than the average user on this forum.
cloudytoday
Interesting, thanks for sharing. In my case, which is mostly about lists crunching, Elixir is many tens of times faster than Python. With some optimizations the advantage becomes many hundreds of times faster even with 5 times larger amounts of data. For example, an imperative algorithm on a list of ~130k dicts in Python would take me about 20 minutes. Trying to rewrite it functionally and seeing the function just get stuck and never return is what made me switch to Elixir
. In Elixir, with an imperative algorithm, I’ve been able to get done with a list of ~500k structs in ~200ms.
Your .exs script is ~1000ms for me, while .py one is ~500ms. Elixir 14.3/OTP 25, Python 3.10.7.
RTLS
Here is a PR that gets the Elixir performance closer to the python performance, though still slower.
https://github.com/fireproofsocks/ex_vs_py/pull/1
I saw from eprof that after
Jason, most time was spent in genservers and cleaning up processes. This is due to theFilemodule opening a new process for every opened file.My PR replaces a lot of these calls with
:prim_filewhich is a nif and does not spawn a process for every file. That also allows theTask.async_streamto help performance; including theasync_streamwhile using theFilemodule just leads to theFilegenserver being a bottleneck.Next you might try improving the json performance, perhaps with
Eljiffy.D4no0
I suspect the stream might be the culprit here, if your file is never that big avoid using stream or read bigger chunks at once.
LostKobrakai
While it’s useful to look at the perf of the erlang code you’d probably also want to evaluate how much of the time is starting up the beam vm. Not sure which otp applications are started by default with mix, but I recently read that they contribute to a good chunk of the startup time for things running on the beam.
hst337
Yeah, but in this benchmark all applications are started before the script is executed
hst337
I’ve modified both scripts to return a list of results and Elixir beats python here.
vs
And the results are 291ms elixir vs 314ms python.
josevalim
Some general remarks for guidance:
Keep in mind the Erlang VM makes specific trade-offs in relation to high-performance, such as process preemption. It is better to have a predictable system that goes slightly less fast than a fast ones that is unpredictable (or crashes)
Streams have lower memory usage at the cost of higher CPU usage. If your goal is to go as fast as you can, not using streams may be better (such as
File.read! |> String.split("\n", trim: true))You should see benefits by adding Task.async_stream and similar so you can leverage multi-core
I would assume that most of the time is taken by JSON parsing so remember Jason is a pure Elixir package. I assume that the json parsing in Python is most likely done in C. So you may have better results by using something like
jiffy(and a more apples to apples comparison)hst337
Most of time is spent on accessing files. I don’t know, but I thought that Erlang team has switched to epoll for prim_file on linux
michalmuskala
Default file IO in Erlang is fairly slow. I’d recommend using it with the
[:raw]option - it bypasses several layers of abstraction that introduce quite a fair bit of overhead.