seanmor5

seanmor5

Author of Genetic Algorithms in Elixir

Enum.take/2 and Enum.drop/2 weird performance

I came across something weird today as I was doing some optimization.

I have a function that splits a list at some point. I was exploring the differences in using Enum.take/2 and Enum.drop/2. I ran some benchmarks on a list of 1,000,000 elements with 4 different scenarios:

  1. Getting the first 500,000 elements using Enum.take(list, 500_000)
  2. Getting the first 500,000 elements using Enum.drop(list, -500_000)
  3. Getting the last 500,000 elements using Enum.take(list, -500_000)
  4. Getting the last 500,000 elements using Enum.drop(list, 500_000)
Name                                          ips        average  deviation         median         99th %
Enum.drop/2 second 500,000 elements        142.99        6.99 ms     ±3.27%        6.97 ms        7.22 ms
Enum.take/2 first 500,000 elements          50.22       19.91 ms    ±33.95%       19.52 ms       26.40 ms
Enum.drop/2 first 500,000 elements          30.62       32.66 ms    ±24.34%       32.35 ms       77.36 ms
Enum.take/2 second 500,000 elements         23.11       43.28 ms    ±19.79%       42.81 ms      112.65 ms

Comparison: 
Enum.drop/2 get second 500,000 elements        142.99
Enum.take/2 get first 500,000 elements          50.22 - 2.85x slower +12.92 ms
Enum.drop/2 get first 500,000 elements          30.62 - 4.67x slower +25.66 ms
Enum.take/2 get second 500,000 elements         23.11 - 6.19x slower +36.28 ms

The results are KIND of as expected. Take is better at retrieving the first half of the list and drop is better at receiving the back half of the list. My real misunderstanding is WHY is drop/2 so much faster than take/2 at doing what it’s intended to do vs. what take is intended to do.

Also, shouldn’t the benchmarks be pretty similar no matter whether you’re dropping or taking forward or backward? Wouldn’t it make sense to just call drop/2 when the second input for take/2 is a negative integer and vice versa with drop/2?

Most Liked

kokolegorille

kokolegorille

Given that lists are linked lists, it makes sense that taking from start is faster than taking from middle. But if You want to optimize this, I would suggest Stream instam of Enum, because it implements lazy loading, while Enum is loading all the list in memory.

I would always add from start, never from the end, then I would reverse the list if needed.

It might not be useful if You just want to split the list…

seanmor5

seanmor5

Author of Genetic Algorithms in Elixir

For my purposes I’ve settled on using Enum.split/2 rather than either take/2 or drop/2. I was just confused as to why there’s such a discrepancy in the performance of these two functions.

What I mean is, why wouldn’t an implementation of drop and take when n is less than 0 look like:

def take(list, n) when n < 0 do
   drop(list, n)
end

def drop(list, n) when n < 0 do
   take(list, n)
end

Shouldn’t this theoretically close the performance gap?

kokolegorille

kokolegorille

I try to avoid this with lists (taking from the middle).

Where Next?

Popular in Discussions Top

jeramyRR
This is an interesting article to read. Elixir’s performance, like usual, is excellent. However, it seems like the high CPU usage is co...
New
laiboonh
Hi all, I am trying to convince my team to use liveview over the current react. What are some of the points where one should consider us...
New
Fl4m3Ph03n1x
Background This question comes mainly from my ignorance. Today is Black Friday, one of my favorite days of the year to buy books. One boo...
New
arpan
Hello everyone :wave: Today I am very excited to announce a project that I have been working on for almost 3 months now. The project is...
New
chuck
Let me start by stating an assumption: Phoenix is a great approach to building REST APIs. There are many reasons for this, but I will ass...
New
crabonature
I’m still quite new to Elixir. As I understand we got in Elixir “multi guards” as convention to simplify one large guard with or’s?: de...
New
tmbb
This is a post to discuss the new Phoenix LiveView functionality. From Chris’s talk, it appears that they generate all HTML on the serve...
342 18146 126
New
boundedvariable
I am going through the kafka architecture. All the features what the kafka is providing are already in Erlang. I would like hear your opi...
New
100phlecs
Are there any downsides, like perf issues, to putting all functional components in CoreComponents as long as you prefix it with the conte...
New
AstonJ
Seen any cool LiveView demos, sample apps or examples? Please post them here! :003:
New

Other popular topics Top

danschultzer
None of the current solutions worked well for me, so I went ahead and built a user management system from scratch. This project took far...
548 29377 241
New
aadeshere1
I have a another noob question about loop. Since elixir is immutable, while loop is not directly possible. total = 10 while total != 0 ...
New
Patoshizzle
After calling mix ecto.create I get this error: 17:00:32.162 [error] GenServer #PID&lt;0.412.0&gt; terminating ** (Postgrex.Error) FATAL...
New
electic
Hi, I am new to Elixir. I am trying to use the DateTime component to insert a date into MySQL however the there seems to be no way to fo...
New
belgoros
I’m not a pro in using Regex and can’t figure out why the following behaviour happens, especially if we take into account the difference ...
New
sergio_101
I am VERY much an elixir newbie. I have taken one elixir course and one phoenix course on Udemy. During that course, I saw the instructor...
New
fayddelight
I tried installing elixir 1.11.2 erlang 23.3.4 via asdf in my zsh shell. Enabled the versions locally and globally. When I list them ...
New
boundedvariable
I am going through the kafka architecture. All the features what the kafka is providing are already in Erlang. I would like hear your opi...
New
PeterCarter
There are pre-rolled solutions for other frameworks that do work. However, Phoenix does not seem to have these. Have people had good expe...
New
svb
Hi! Currently I want to submit a form by pressing the Enter key. However, since my input field is of type “textarea” this is just adds a...
New

We're in Beta

About us Mission Statement