今更だけど qiita でたまたま目についたので Golang ではどんなものなのかやってみた。
他の言語についてはここから参照されたし。
実行環境
OS: Ubuntu 14.04 LTS
CPU: Intel(R) Core(TM) i7-4510U CPU @ 2.00GHz
言語: go version go1.3 linux/amd64
ソースコード
まずは愚直にやってみたバージョン。
他の言語と比べてもかなりシンプルな方ですね。
bruteforce.go
package main
import (
"crypto/md5"
"fmt"
"os"
"bytes"
"encoding/hex"
)
const NUMMAX = 1000000
func main() {
pw, _ := hex.DecodeString(os.Args[2])
for i := 0; i < NUMMAX; i++ {
sum := md5.Sum([]byte(fmt.Sprintf("%s$%06d", os.Args[1], i)))
if bytes.Equal(pw, sum[:]) {
fmt.Printf("Solved: %06d\n", i)
return
}
}
}
実行結果
shell
$ time go run bruteforce.go hoge 4b364677946ccf79f841114e73ccaf4f
Solved: 567890
real 0m0.566s
user 0m0.540s
sys 0m0.027s
なんとコンパイル込みで約0.56秒でした。
この時点で結構早かったので高速化する気が一気に失せました。。。
ちなみにコンパイルして実行した結果は以下の通り。
shell
$ go build bruteforce.go
$ time ./bruteforce hoge 4b364677946ccf79f841114e73ccaf4f
Solved: 567890
real 0m0.445s
user 0m0.434s
sys 0m0.012s
コンパイルにかかっている時間は0.1秒のようです。
普段Scala使ってるとこのコンパイル速度は驚異的ですね!
続いて、皆さん並列実行版も計測してらっしゃるので、Goroutine版も用意しました。
並列化してもコードはシンプルでいいですね!
bruteforce2.go
package main
import (
"crypto/md5"
"fmt"
"os"
"bytes"
"encoding/hex"
"runtime"
"sync"
)
const NUMMAX = 1000000
func main() {
numCPU := runtime.NumCPU()
runtime.GOMAXPROCS(numCPU)
pw, _ := hex.DecodeString(os.Args[2])
var wg sync.WaitGroup
var once sync.Once
wg.Add(1)
for i := 0; i < numCPU; i++ {
go func(start, step int) {
defer once.Do(wg.Done)
for j := start; j < NUMMAX; j += step {
sum := md5.Sum([]byte(fmt.Sprintf("%s$%06d", os.Args[1], j)))
if bytes.Equal(pw, sum[:]) {
fmt.Printf("Solved: %06d\n", j)
return
}
}
}(i, numCPU)
}
wg.Wait()
}
実行結果
shell
$ go build bruteforce2.go
$ time ./bruteforce2 hoge 4b364677946ccf79f841114e73ccaf4f
Solved: 567890
real 0m0.256s
user 0m0.812s
sys 0m0.028s
約0.25秒でした。
個人的にはもっと速度出てほしかったですけど、十分かな?
Ultrabookでこの速度なので、デスクトップとか4コアとかのCPUだともっと早いと思う。
まとめ
Golang で書いたコードは速いし書くのは簡単だし、オススメ