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
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
- #elixirconf
- #channels
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #blog-post
- #ai
- #phoenix_html
- #elixirconf-us
- #iex
- #graphql
- #genstage
- #websockets
- #supervisor
- #advent-of-code
- #distillery
- #processes
- #api
- #forms
- #hex
- #security
- #metaprogramming










Showing Posts 23 to 14- Show Best Posts
- Show All (oldest first)
- Show All (newest first)
cro
Yeah, like Java. We did a PoC at work and “bare” Java (no Spring, Hibernate, or anything but the bare minimum for external libraries) blew away Elixir, Python, and Go, and came in second only to C.
For our use case Elixir was faster than Python. However, one thing came to light in our PoC that was interesting–Python’s concurrency story is still not great. Async/await code is super hard to reason about and debug. There is very little visibility into the event loop in Python async code, and async code tends to proliferate in your codebase since you can’t call
awaitfrom a nonasyncfunction. So when you need to call a coroutine withawaitthe calling function must becomeasync…which means it’s calling function will need toawaitit and becomeasync. There are ways around this but they are non-obvious and make your code complex.The Elixir/BEAM approach is so, so much better. Not that it is a silver bullet for complex systems, but if you are writing a large scale system that depends heavily on concurrency for performance, I would choose Elixir over Python.
That’s not even getting into the additional DX issues–introspectability, observability, multi-node deployments, the list goes on.
dogweather
Python has had a lot of speed optimization go into it over the years. I’m not too surprised that a first solution turned out to be pretty good.
fireproofsocks
I tried this (building off of the previous performant solution):
I streamed the file with this code (I think I’m probably reinventing wheels here, but it was educational):
This performed more or less the same as the other solutions.
BradS2S
Ok so :file.read_line and go through all the lines?
fireproofsocks
Reading chunks of data (instead of lines) is awkward in this case because each line contains a value. When processing chunks, you have to manually split on newlines and reassemble any values that got split. (At least, I need more coffee before I can come up with a solution to that). Also
:file.read/2returns charlists, and I’m not sure what kind of overhead it would be introducing to convert those back into strings.fireproofsocks
Just for the record, that was my Python code and I made no attempts to optimize – I just poked at it for a few minutes until it worked.
D4no0
Is that so? Only because you are using a python function to call the library function is doesn’t mean there isn’t a native C implementation under the hood.
What about the abomination the python is at this moment in time? Nobody can’t understand at this point if the language is interpreted or compiled anymore because of how many optimizations are in place to make it fast.
If you are just getting in elixir you might be thinking that using an erlang library is strange and it is the same as calling C code, however this is definitely not true as elixir gets compiled to erlang, so no overhead is involved here.
Moreover if you have access to 2 separate languages and ecosystems without any setup and overhead why not use whats best from both worlds?
Is that so? What about concurrency? The elixir solution above is either using tasks or streams and you are showing a solution that can run only in a blocking manner.
BradS2S
I’d be curious how it would do against raw file
dogweather
I’m interested in Elixir solutions that are not only faster, but also as clean and naive as the Python solution (from above). It doesn’t use any special Python libraries. It doesn’t obviously drop into C code (like the best Elixir version uses Erlang functions and types. ?)
This is very clean code (literally, in Bob Martin’s Clean Coding style.)
fireproofsocks
Thank you all for the continued input. This is interesting! I formalized my repo to use Benchee so I could continue trying out some variants. Here are the results (so far):
In short, Python is still the fastest. The fastest Elixir solution (so far) is the one that uses
Task.async_streamand the:prim_file:I tried variants that used EITHER
Task.async_streamOR:prim_file, but they didn’t perform as well. Loading the file into memory instead of streaming it also didn’t perform as well. I haven’t been able to get jiffy working, so I gavejsonrsa try, but unfortunately, it performed the worst of these (!!).What is challenging here is that the solutions have very different performance characteristics. In other words, it’s easy to fall into a hole here, so I’m hoping to identify patterns to avoid. I should probably try coming up with more simplified use-cases, because this one touches on a lot of things: streaming, checking the file system, and JSON decoding.