πΎ Archived View for ser1.net βΊ post βΊ ruby-vs-go-fight.gmi captured on 2024-03-21 at 15:08:44. Gemini links have been rewritten to link to archived content
β¬ οΈ Previous capture (2022-07-16)
-=-=-=-=-=-=-
--------------------------------------------------------------------------------
title: "Ruby vs. Go... FIGHT!" date: 2012-02-14T09:14:00Z
--------------------------------------------------------------------------------
Only sorta-kinda. Β I've been trying to use Go for some tasks for which I'd normally reach to Ruby; most recently was grabbing some date elements from a large-ish XML file. Β I know, I know... Ruby has the best XML library ever[1]Β built into it, but I'm more aware than anybody of the performance issues it has, so I tend to use it for only very small files. Β So when I needed to extract some information out of this fat XML, I thought I'd try Go.
1: http://www.germane-software.com/software/rexml/
The file wasn't so big that I was worried about memory use, but since I only needed a leaf from each branch of the tree, I chose the SAX-ish API anyway. Β That's going to make any code more bloated, but it wasn't too bad; the results are in Version 1[2].
2: http://pastebin.com/ugGzmMvN
After I got everything working, I got to wondering about the performance, so I wrote it again in Ruby[3]. Β I did **not**Β try to use the same logic; instead, I did it in what, for me, is more idiomatic Ruby code. The timings (I chose the average-looking times; I did not properly benchmark these, but I did run each program several times and then grabbed the middlin' looking one), which may or may not be surprising, look like this:
3: http://pastebin.com/qCtuVgMj
ββββββββββββββββ¬βββββββββββ¬βββββββββββββββββ¬ββββββββββββ β Version β Language β Total time (s) β CPU usage β ββββββββββββββββͺβββββββββββͺβββββββββββββββββͺββββββββββββ‘ β Version 1[4] β Go β 0.113 β 96% β ββββββββββββββββΌβββββββββββΌβββββββββββββββββΌββββββββββββ€ β Version R[5] β Ruby β 0.099 β 66% β ββββββββββββββββ΄βββββββββββ΄βββββββββββββββββ΄ββββββββββββ
"Hmmm", I hear you say. Β Well, the Go version *is*Β actually parsing the XML, and we all know XML for the bloated, expensive-to-parse format that it is. Β OTOH, Ruby is doing regexp on every line, and is additionally reading the entire file into memory first and splitting it into an array on line endings. Β Hmmm. Well, let's try a Go version that is a little more like the Ruby version. Β That's Version 2[6]:
4: http://pastebin.com/ugGzmMvN
5: http://pastebin.com/qCtuVgMj
6: http://pastebin.com/Hun5kKYc
ββββββββββββββββ¬βββββββββββ¬βββββββββββββββββ¬ββββββββββββ β Version β Language β Total time (s) β CPU usage β ββββββββββββββββͺβββββββββββͺβββββββββββββββββͺββββββββββββ‘ β Version 2[7] β Go β 0.284 β 103% β ββββββββββββββββ΄βββββββββββ΄βββββββββββββββββ΄ββββββββββββ
Yowsa! Β That's going in the wrong direction. Β Interestingly, it's now using more than one core of my CPU, so it's doing something thready underneath. Β Maybe it's because I'm reading the file line-by-line off the disk? Β Let's make it even more like the Ruby version; Version 3[8]:
7: http://pastebin.com/Hun5kKYc
8: http://pastebin.com/2sZ91GH9
ββββββββββββββββ¬βββββββββββ¬βββββββββββββββββ¬ββββββββββββ β Version β Language β Total time (s) β CPU usage β ββββββββββββββββͺβββββββββββͺβββββββββββββββββͺββββββββββββ‘ β Version 3[9] β Go β 0.292 β 105% β ββββββββββββββββ΄βββββββββββ΄βββββββββββββββββ΄ββββββββββββ
Definitely going in the wrong direction. Maybe it's the sre2 library? Let's try Version 4[10]:
9: http://pastebin.com/2sZ91GH9
10: http://pastebin.com/qjcSyR5M
βββββββββββββββββ¬βββββββββββ¬βββββββββββββββββ¬ββββββββββββ β Version β Language β Total time (s) β CPU usage β βββββββββββββββββͺβββββββββββͺβββββββββββββββββͺββββββββββββ‘ β Version 4[11] β Go β 0.037 β 89% β βββββββββββββββββ΄βββββββββββ΄βββββββββββββββββ΄ββββββββββββ
Ok, that's better. Armed with this, I went back to not reading the file entirely into memory in Version 5[12]:
11: http://pastebin.com/qjcSyR5M
12: http://pastebin.com/QTAyuddg
βββββββββββββββββ¬βββββββββββ¬βββββββββββββββββ¬ββββββββββββ β Version β Language β Total time (s) β CPU usage β βββββββββββββββββͺβββββββββββͺβββββββββββββββββͺββββββββββββ‘ β Version 3[13] β Go β 0.292 β 105% β βββββββββββββββββΌβββββββββββΌβββββββββββββββββΌββββββββββββ€ β Version 2[14] β Go β 0.284 β 103% β βββββββββββββββββΌβββββββββββΌβββββββββββββββββΌββββββββββββ€ β Version 1[15] β Go β 0.113 β 96% β βββββββββββββββββΌβββββββββββΌβββββββββββββββββΌββββββββββββ€ β Version R[16] β Ruby β 0.099 β 96% β βββββββββββββββββΌβββββββββββΌβββββββββββββββββΌββββββββββββ€ β Version 4[17] β Go β 0.037 β 89% β βββββββββββββββββΌβββββββββββΌβββββββββββββββββΌββββββββββββ€ β Version 5[18] β Go β 0.034 β 91% β βββββββββββββββββ΄βββββββββββ΄βββββββββββββββββ΄ββββββββββββ
Not a lot of difference; I did see a couple of runs where the CPU use dropped to 89% without affecting the total time, but these are pretty small numbers and we could be seeing actual run time being overwhelmed by the program initialization and what-not.
13: http://pastebin.com/2sZ91GH9
14: http://pastebin.com/Hun5kKYc
15: http://pastebin.com/ugGzmMvN
16: http://pastebin.com/qCtuVgMj
17: http://pastebin.com/qjcSyR5M
18: http://pastebin.com/QTAyuddg
Anyway, I thought it was interesting. Β Ruby is slow as all get-out, but for micro-tasks where most of the heavy lifting is running in native C (regexp in Ruby is native, as is IO), it's more than capable enough. It's also worth noticing that this was with ca. 30 lines of Go code, vs. 8 lines of Ruby code.