Le 26 août 2013 00:25, "TR NS" <tran...@gmail.com> a écrit :
>
> I recently wrote a program that uses a genetic algorithm to determine the most ergonomic layout of a keyboard (a rather esoteric type of keyboard that I am working on). I originally wrote the program in Ruby, but it was very slow. So I decided to rewrite in another language. After some investigation I decided to write it twice, once in Go and then in Elixir. I thought it would a good way to get a feel for both of these new languages and to directly see how they compare.
>
> Going into the project I fully expected the Go program to be the fastest and the Elixir program to be easier to write. Turns out I was dead wrong on both counts. The Go program I was able to knock out in just over a day. it was pretty easy. The Elixir program on the other hand took me 4 times that to work out. Functional programming can be a real mind bender! However the Elixir program could churn out results at a rate 20x faster than the Go program!!! The Go program was still faster than the Ruby, but not nearly by such a large margin.
>
> Honestly I am rather disappointed. I really liked coding in Go. But the performance gain isn't enough to make it worth while. And I can't understand why it is so slow either. I surmised perhaps the Elixir code was taking advantage of my dual core processor, where as the Go code was not, but I still find that hard to account for a 20x difference.
>
Your Go code is highly unidiomatic and inefficient. The array.go file shouldn't even exist.
> So I thought I'd ask, if anyone has the patience to look over the code, perhaps there is something I am doing terribly wrong that explains it?
I think you should wait and be more experienced in both languages before doing a comparison: benchmarks are biased if you know a language better than the other.
Eliminate quadratic algorithms, use appropriate data structures. Use maps wisely.
> One thing I am looking at doing that might help is utilzing go routines. I suspect that will help some, but I doubt it will help 20 fold. Unfortunately I am finding that a little tricker than I thought it would be too, to go back and insert the use of go routines.
No, goroutines don't improve efficiency. They just bother more CPUs.
> You can see all the code here: https://github.com/tabcomputing/corpus (FYI the Ruby version is a little out of data compared to the other two).
>
> Appreciate any insights.
>
Please try profiling your program. You may find this package useful,
github.com/davecheney/profile.
Highlights:- Run gofmt.- Make your code goinstallable -- that is, import it as "github.com/tabcomputing/corpus/go/keyboard" not "corpus/keyboard"
- Ditch the arrays.go file -- those are crazily inefficient or unnecessary in pretty much every case.
- Use "sync".Once instead of your cache thing- Use rand.NewSource (one per goroutine), so you don't have a lock to fight with- Use Perm for your shuffling
You'll need to install ghostscript to use gv/pdf/web. Having said
that, I don't think you've profiled correctly, there is no function
called etext in your supplied program, did you profile the correct
thing ?
Ok. `rand.Perm(myList.size)`, not how do I apply this random list of indexes to `myList` no get the shuffled list? Do I still need to iterate over the indexes and build-up a new array or is there something built-in I can use?
On Sunday, August 25, 2013 7:59:48 PM UTC-4, Kyle Lemons wrote:
Thanks for the suggestions. A couple follow-ups:Highlights:- Run gofmt.- Make your code goinstallable -- that is, import it as "github.com/tabcomputing/corpus/go/keyboard" not "corpus/keyboard"
- Ditch the arrays.go file -- those are crazily inefficient or unnecessary in pretty much every case.
Do you mean there are other ways to do all of these things?
- find index of element in array
- determine if element is a member of an array
- detect duplicates elements
- swap two elements in an array given two indexes
--
If you take a step back, I think you'll find that you can represent each population as a member slice that never changes and an index slice that chooses which members are present in that population. You can probably add extra fields to that struct that make it so that the other operations (e.g. membership, dedup) are O(1) or unnecessary.
They are after all essentially the same program