prxssh

prxssh

Any tips or learning resources for writing highly performant Elixir code?

I’ve been writing Elixir and Phoenix professionally for the past year and have grown quite fond of them. I’ve read books like Elixir in Action, Concurrent Data Processing in Elixir, and Designing Elixir Systems with OTP.

I’m keenly interested in writing highly performant code in Elixir. Obviously, achieving performance levels like Go, C++, or Rust isn’t possible, and I understand that. However, I suspect there might still be some hidden tricks to make Elixir code more performant.

Could anyone point me towards any source material, books, talks, etc., that dive into the performance aspects of Elixir?

Most Liked

rkallos

rkallos

Without much more information about what you want your code to do, I can only offer more general advice to think about when writing code, as a supplement to Eiji’s great advice.

Do less.

It should not be surprising that code that does less usually finishes faster than code that does more. Applying this advice could look like:

  • Refactoring traversals of collections to traverse less, ideally once. (Echoed in Eiji’s post).
  • Performing fewer deep structure updates. While updates to immutable data are efficient from a VM perspective, they’re not free. Certain updates to data structures are much cheaper than others, and you should try and use those whenever possible. For example, building iolists can be much faster than repeatedly constructing binaries.

Using :ets, :atomics, and more.

Erlang’s standard library contains modules that can be a great help when writing code that needs high performance. :atomics and :counters are great for working with collections of integers that must be updated atomically. :persistent_term is very useful for accessing read-only data from many processes.

ETS is a more general-purpose tool, and learning to wield it well can dramatically improve performance in many situations.

Read the Erlang Efficiency Guide

Reading, and more importantly, understanding the advice written in the Erlang Efficiency Guide should take you pretty far along your journey to writing high-performance code that runs on the BEAM. The guide does a great job of explaining why certain code runs more slowly, and communicates useful insight to the BEAM VM that you can keep in your mind when you code.

Know when to stop

While it is very satisfying to write code that runs very quickly, certain optimizations and refactorings done in the name of performance can have a strong negative impact on the readability, testability, and maintainability of your code. To quote the late, great Joe Armstrong:

Make it work, then make it beautiful, then if you really, really have to, make it fast. 90 percent of the time, if you make it beautiful, it will already be fast. So really, just make it beautiful!
– Joe Armstrong, Erlang & OTP in Action

11
Post #4
dimitarvp

dimitarvp

The most performance I managed to eke out of Elixir was:

  1. When I parallelized the algorithm. The BEAM VM just absolutely excels at parallel programming.
  2. When I made sure to not copy and pass a lot of data around i.e. if you need to periodically access stuff that’s several kilobytes it’s probably best to put it in ETS and just pass names / references to your workers – and not the data itself. That’s also quite true for any programming language btw; you can make an otherwise quick Rust program crawl down to JS / Golang level if you just constantly copy / clone data. (BTW it really must be said that this very strongly depends on the data, the algorithm, the amount of workers etc.; I also had success with just directly passing the data to workers and was confused as to why using ETS didn’t net me a performance win… until I realized that pulling data out of ETS copies them as well – so it’s all copying in the end but many other parameters in the equation can tilt the result one way or the other. Just measure.)

There are many more that could be inferred by production experience but these were my top 2 every time. I’d say you’ll have more success if you just try your hand at something and if you are not satisfied with the results, come back to the forum and we’ll give you guidance on per-case basis.

lawik

lawik

Nerves Core Team

Michal Muskala who built Jason and the new Erlang :json gave a talk about a lot of how he made it fast. It was given at Code BEAM Berlin last year and should show up online in January or February I believe.

I was there, heard it. Found it quite interesting :slight_smile:

JEG2

JEG2

Author of Designing Elixir Systems with OTP

Nine times out of ten, in my career, the biggest wins have from finding better ways to model the data (MapSet, :ordset, and :digraph have helped with this in Elixir code) and figuring out how to skip steps with better algorithms. My new Livebook series, How to Train Your Scrappy Programmer, covers a lot of those techniques (using several practices mentioned in this thread and others). I would say that the two Livebooks most heavily covering this topic are Borrowing a Cup of Algorithms and Charting Our Course. There’s also some of this thinking in the free download: Data and the Code That Loves It.

Eiji

Eiji

They are - just use NIFs :wink:

There are lots of possible improvements, for example:

  1. Depending on specific case i.e. you have 2 or more algorithms, benchmark them using benchee and use desired solution
  2. NIF and related language features not only can speed up code, but also allows to use many non-Elixir libraries.
  3. Stream, Flow and other modules instead of Enum - instead of storing whole enumerable in memory we can read and process them separately… Similarly we can process multiple list elements at the same time. There are lots of solutions depending on what you want to achieve
  4. Metaprogramming i.e. improve runtime code by for example generating a pattern-matching
  5. Try to limit piped Enum calls, so iterate one list as few times as possible, often [head | tail]-based recursive function or Enum.reduce/3 is useful in such cases.

Please remember that there is no #1 optimisation. Sometimes you optimise resources usage and sometimes you use all available resources to speed up the work. Also it’s worth to mention that raw speed it not always welcome if you have to write very strict code. Often writing more generic code without every possible optimisation may save you huge amount of time in case you would be rewriting or enhancing it by supporting more structs and so on … Again, there is no a single good solution here as it’s very case-specific topic.

Where Next?

Popular in Chat/Questions Top

ariandanim
Hello all, I am still learning Elixir, then go into Phoenix, i am try search in google but find the programming phoenix 1.4, another for...
New
LegitStack
I’m not a hugely experienced programmer, just a few years. So I’m looking for resources to learn about a topic but I can’t seem to find m...
New
svetarosemond
I’m planning on purchasing Elixir in action second edition, and I was wondering if anyone could tell me based off the first edition, does...
New
asfand
I already created an Elixir Phoenix app for learning purpose. In this app students of our collage will create profiles, and will chat wit...
New
Fl4m3Ph03n1x
Background Hello all! So after my controversial introduction with Learning Elixir, frst impressions ( plz don’t kill me ! ) - I saw a ton...
New
Chawki
Hi,i’m new to elixir. i’m searching elixir small programs to try it out my self,Is any good resources out there? Thank you.
New
pillaiindu
I am a VSCode and Sublime user and I know VIM, though I don't use VIM directly but whenever I code inside Sublime or VSCode, I use Vim em...
New
phykos
In Ruby, which is very similar to Elixir I do this: def test yield end test do puts("sup there") end Here, the yield keyword will be...
New
AstonJ
It’s been a while since we asked this - I’m sure others (especially newcomers to the language) will be interested to hear how you’ve all ...
New
Twfo326
As a novice dev I’m trying to keep the curriculum as lean as possible. My requirements are modest: build simple CRUD apps with Phoenix...
New

Other popular topics Top

JDanielMartinez
Hi! May someone helps me, please! I have two apps into an umbrella project: the first one is Database, which manages queries, and the se...
New
Brian
What is the proper way to load a module from a file in to IEX? In the python world, doing something like this pretty standard: from ....
New
bsollish-terakeet
Credo is smart enough to check for (something like) this: assert length(the_list) == 0 with this response: Checking if an enum is empt...
New
JorisKok
I have a server on AWS, and was running a load test using artillery. When looking at the Phoenix dashboard I see the Ports going to 100% ...
New
jerry
Good day to you all. I have been struggling to get a query involving like and ilike to work. Can anyone assist me on this, please? pro...
New
grych
Hi folks, Few months ago I have announced the proof-of-concept of the library to manipulate the browsers DOM objects directly from Elixi...
639 49522 488
New
Harrisonl
We have an ECS cluster with 4 services, where each task joins a single cluster, via discovery ECS discovery service. Currently when I de...
New
chensan
I have a User schema with a :from_id field set to type :string: defmodule TweetBot.Repo.Migrations.CreateUsers do use Ecto.Migration ...
New
ashish173
I am using Ecto timestamps with postgres, I can see the timestamps() use the :naive_dateime but for my use case I wanted to store the ti...
New
qwerescape
Is there a way to get the call stack or stack trace at any point in the code? Not from exceptions, but an expression that returns how the...
New

We're in Beta

About us Mission Statement