Slow performance compared to legacy
monkeygroover opened this issue · comments
So... I was trying Advent of Code and solved day 6 but only in legacy:
however this is too slow in the elixir version, not sure why yet, stack recursion perhaps?
This appears to be because rotate becomes more and more inefficient if done repeatedly on a stream, If do this:
def rotate(value, shift) when shift == 0, do: value
def rotate(value, shift) when not Functions.is_iterable(value), do: Enum.join(rotate(String.graphemes(to_string(value)), shift), "")
def rotate(value, shift) when shift > 0 do
case Enum.count value do
0 -> []
x ->
shift = rem(shift, x)
Stream.concat(value |> Stream.drop(shift), value |> Stream.take(shift)) |> Enum.to_list
end
end
def rotate(value, shift) when shift < 0 do
case Enum.count value do
0 -> []
x ->
shift = rem(shift, x)
Stream.concat(value |> Stream.take(shift), value |> Stream.drop(shift)) |> Enum.to_list
end
end
It's very fast again.
Not sure if there are any downsides, going to run the tests. But using rotate on large streams probably isn't a good idea anyway.
Yeah, there were a couple of downsides after rewriting this from Python to Elixir. Performance was indeed one of the biggest regressions.
Both versions have bugs, this one is just less buggy hahaha. Ideally I would rewrite it again in Scala or Java (or some other strongly typed language), but I can barely find the time for doing so unfortunately.
Yeah, Rust may work too (but no GC, so lots to learn)
I actually did this to get some clues: https://github.com/monkeygroover/05AB1E/tree/flame hacky but helped!
Oohh, that is clever!
I will definitely have to check that out, thanks for sharing! :)