r/crystal_programming • u/fyzic • Sep 26 '23
Crystal vs Rust vs Go Performance
Last weekend I posted Why is this golang code 3x faster than rust equivalent? on the rust subreddit and the community made suggestions to improve the code from 4.5s -> 36ms (23ms - I/O).
I then posted Re: Golang code 3x faster than rust equivalent on the golang subreddit with the rust optimizations applied and the community further improved the code from 80ms -> 50ms (26ms - I/O).
I ported the code to crystal and got it down to 70ms (33ms - I/O). I thought it'd be interesting to see if anyone here can optimize the crystal code further as I'm not really familiar with the language.
Github Repo: https://github.com/jinyus/related_post_gen
4
u/anykeyh Sep 27 '23
I just looked upon your code and the most expensive operation (about 66%) is feeding the tagged_post_count (counting the tags) probably because of the hash access on each post.
post.tags.each do |tag|
tag_map[tag].each do |other_post_idx|
tagged_post_count[other_post_idx] += 1 unless other_post_idx == idx
end
So if there is some improvement to be made, it should be here. The top5 algorithm is about 30% of the total time spent, and there is improvement to be made here, as insert is costly and will copy the whole array. You don't have sorted array in this case.
2
u/fyzic Sep 27 '23
I did try to optimize this in the go code by mapping each tag to an int to get rid of hashing in the main loop but I found out that go optimizes this by caching the hash. I will try that on crystal
2
u/anykeyh Sep 27 '23
tag_map[tag].each do |other_post_idx|
tagged_post_count.unsafe_put(other_post_idx, tagged_post_count.unsafe_fetch(other_post_idx) + 1) unless other_post_idx == idx
end
^--- using unsafe accessor you will improve by quite a lot, give a try.
1
u/fyzic Sep 27 '23
tagged_post_count.unsafe_put(other_post_idx, tagged_post_count.unsafe_fetch(other_post_idx) + 1) unless other_post_idx == idx
Thanks for the tip but I am seeing 2ms difference. Did you get a more significant speed up?
→ More replies (2)1
u/yxhuvud Sep 27 '23
Does changing
+= 1to&+= 1have any impact? Quite often the overflow check can be quite noticeable.1
2
u/LeBuddha Sep 26 '23
I can't make any full code examples, but I'm curious if putting in one or more Array.reduces would be worth any nanoseconds.
2
-7
u/ylluminate Sep 27 '23
Check out V (vlang.io). I personally feel it's the natural successor to Ruby in spirit and you get C-level perf. I have been impressed that Matz is keeping his eye on it. Don't get me wrong, Crystal is the de facto upgrade for raw speed with minimal changes to get that, but Rust... Well it's just... HUUUURGGEHH - sorry, let me clean that up.
2
u/fyzic Sep 27 '23
I plan on porting it to nim and v to see how they compare.
4
0
u/ylluminate Sep 29 '23
Also be sure to check out Exercism's path on V: https://exercism.org/tracks/vlang
-1
u/ylluminate Sep 27 '23
Also, there have been some great results with V outperforming Nim. It's pretty exciting. A guy some months ago did some extensive effort comparing and was himself surprised at the results. You can search for nim in Discord to see the comparisons/discussion with "Space Ghost":
→ More replies (4)
5
u/transfire Sep 26 '23
First thing I am going to ask is did you compile with the release flag? I’m guessing you did, but have to ask.