2016年12月31日土曜日

RubyとGolang で並行処理のパフォーマンス比較してみた。(引用日2016年12月31日)

勉強の為に引用しました。
http://blog.toshimaru.net/ruby-vs-go/

05 Mar 2015  ruby go
Rubyで書いたコードがGoで書いたらどれくらい早くなるかを検証したくてやってみた。画像ファイルをダウンロードするだけの単純な処理での比較。(複雑な処理になるとまた全然違ってくると思います)

Rubyの場合

イメージを100個ダウンロードするコードをサンプルにやってみました。

直列にダウンロード

何も考えず1つ1つダウンロードするコード。

require 'open-uri'

(1..100).each do |i|
  open("./images/#{i}.png", 'wb') do |f|
   f.write open("http://dummyimage.com/600x400").read
  end
end
$ time ruby no_thread.rb
ruby no_thread.rb  0.25s user 0.10s system 1% cpu 29.813 total
約30秒。遅い。そしてCPUコストは低い。

Threadで並行ダウンロード

Thread使って並行に処理してみる。

require 'open-uri'

thr = []
(1..100).each do |i|
  thr << Thread.new do
    open("./images/#{i}.png", 'wb') do |f|
      f.write open("http://dummyimage.com/600x400").read
    end
  end
end
thr.map(&:join)
$ time ruby thread.rb
ruby thread.rb  0.20s user 0.10s system 27% cpu 1.105 total
1.1秒。劇的な改善。CPUは30%くらい使ってる。

Goの場合

Goで書きなおしてみる。

こちらを参考に書いてみた。

package main

import (
"fmt"
"io"
"net/http"
"os"
"sync"
)

func main() {
var wg sync.WaitGroup

for i := 0; i < 100; i++ {
wg.Add(1)
var url string = "http://dummyimage.com/600x400"

//ファイルを開く
file, err := os.Create("images/" + fmt.Sprint(i) + ".png")
if err != nil {
panic(err)
}

go func() {
response, err := http.Get(url)
if err != nil {
panic(err)
}
//レスポンスのボディを閉じる関数の遅延実行指定
defer response.Body.Close()

//fmt.Println("status:", response.Status)

//ファイルを閉じる関数の遅延実行指定
defer file.Close()

//レスポンスのボディから読み込みつつファイルに書き出す。
io.Copy(file, response.Body)
wg.Done()
}()
}

wg.Wait()
}
Go run で実行

コンパイルせずにgo runで実行してみる。

$ time go run sample.go
go run sample.go  0.50s user 0.21s system 50% cpu 1.413 total
1.4秒。Thread使ったRubyのコードと同じくらい。

Go build :arrow_right: Run

buildして実行する。

$ go build sample.go
$ time ./sample
./sample  0.06s user 0.07s system 16% cpu 0.789 total
約0.8秒。Rubyで書いたコードの3/4の時間で完了した。

今回は単純な処理なのでRubyとGoの間で大きな差は生まれなかったものの、比較するロジックが複雑化すればするほどGoのパフォーマンスの良さがガッツリと効いてきそう。CPUコストがRubyより半分程度に済んでいるところもナイス。

【番外編】Shell Script で実行

for i in `seq 1 100`; do
  wget --background --quiet "http://dummyimage.com/600x400" -O images/$i.png > /dev/null
done
$ time bash bash_script.bash
bash bash_script.bash  0.15s user 0.24s system 72% cpu 0.547 total
約0.5秒。はやい。 :astonished:

CPUも超使ってる。

0 コメント:

コメントを投稿