post Image
【半端ないって】ビギナーPHPerが叫ぶGoの処理速度半端ないって

グレンジ Advent Calendar 2018 23日目の記事を担当しますkitaji_ngzkと申します。

昨年度はデータマイニングに従事していてその際使っていたTableauについての記事を書きました。
↓↓ちなみにコチラ↓↓
https://qiita.com/kitaji_ngzk/items/6ecdd69f720a9aa033df

今年度はサーバーサイドの業務に従事していて、そこではPHPを扱っております。

さて、今回私が紹介するのは
ビギナーPHPerが叫ぶGoの処理速度半端ないって
ということで、
エンジニア歴8ヶ月なビギナーPHPerである私が
GoとPHPを超簡単に比較してみた実験報告をさせていただきまっす!!

というのは最近よくGoを取り扱う企業さんやプロジェクトの発表や報告を目にするなと思っており・・・というよくある流れでGoを知り、速い!とか標準ライブラリが豊富!といった良い情報を耳にするので、実際に比較実験してみました!

ただ、ぺーぺーな自分は高テクニックなかっこいいコードなど書けませんorz

ので、超簡単に「sampleという文字列に数字をつけたしていくのをforでぐるぐる10万回回して配列に入れていくという処理を3回繰り返す」をPHPとGoでそれぞれ作り、メモリ使用量と処理時間を比較したいと思います。

使用環境

macOS Mojave v10.14.1
PHP v7.1.19
Go v1.9.4

PHP

PHPでの実装は以下になります

sample.php
// メモリ使用量と開始時間取得
$baseMemoryUsage = memory_get_usage();
$baseTime = microtime(true);

// 将来的に3つのテーブルに10万レコードのテストデータを入れることを想定
$maxTableCount = 3;
$maxRecord = 100000;

$userList = [];
for ($k = 1; $k <= $maxTableCount ; $k++) { 
    for ($i = 1; $i <= $maxRecord; $i++) {
        $userList[] = 'sample' . sprintf('%06d', $i);
    }
}

printf(count($userList) . "\n");

// 処理後のメモリ使用のピーク量と処理にかかった時間取得
$memoryUsage = (memory_get_peak_usage() - $baseMemoryUsage) / (1024 * 1024);
$processTime = microtime(true) - $baseTime;

printf("Memory Usage : %.3f [MB]\n", $memoryUsage);
printf("Process Time : %f [ms]\n", $processTime * 1000);

Go

Goでの実装は以下になります

sample.go
package main

import (
    "fmt"
    "runtime"
    "time"
)

// ステータス定義
type status struct {
    memory uint64
    time   time.Time
}

var mem runtime.MemStats

// メモリ使用量と時間を取得
func (s *status) GetStatus() *status {
    s.time = time.Now()
    runtime.ReadMemStats(&mem)
    s.memory = mem.Alloc
    return s
}

// ステータス初期化
func NewStatus() status {
    return status{}
}

const (
    maxTableCount = 3
    maxRecord     = 100000
)

func main() {
    // メモリ使用量と時間取得
    status := NewStatus()
    status.GetStatus()
    memoryStart := status.memory
    timeStart := status.time

    var userList []string
    for k := 1; k <= maxTableCount; k++ {
        for i := 1; i <= maxRecord; i++ {
            userList = append(userList, fmt.Sprintln("sample" + fmt.Sprintf("%06d", i)))
        }
    }

    fmt.Println(len(userList))

    // メモリ使用量と時間取得
    status.GetStatus()
    memoryEnd := status.memory
    timeEnd := status.time

    fmt.Printf("Memory Usage : %f [MB]\n", float32(memoryEnd - memoryStart) / (1024 * 1024))
    fmt.Printf("Process Time : %f [ms]\n", (timeEnd.Sub(timeStart)) . Seconds())

}

結果

$ php sample.php
300000
Memory Usage : 27.448 [MB]
Process Time : 52.204847 [ms]
$ go run sample.go
300000
Memory Usage : 10.546051 [MB]
Process Time : 0.187551 [ms]

スピードは圧倒的でした。びびるレベルで速い。

調べてみると大きく起因してるのはPHPがインタプリタ言語、Goがコンパイル言語ってことっぽいです。
いわゆる処理実行のたびに解析するか、先に解析させてまとめて処理させるかってとこで大きく差が出るみたいですね。

割り当てられたメモリの量も約1/3!こちらも半端ないっすね汗
いいことずくめじゃないですか٩(๑•̀ω•́๑)۶
ただ実際内部で配列の持ち方が違ったりとかあると思うので、一概にイーブンで比較してるわけではないかもですが、
ここまで差が開くのはすごいなと思いました!

所感

やはり自分で体感してみて、Goは速いに尽きました。
自分はソーシャルゲーム開発に携わっている身ですが、ゲームプロダクトでGoを採用しているのはまだ聞いたことがないです。でも、活かせる部分はあるのではないかとは思いました。
特にリアルタイム同期やレスポンス速度重視な処理などでは活躍できるんじゃないかなと思うので、検証する余地はありそうです。

あとはGoはめちゃめちゃ書きやすかったです(もちろん最初のお作法のお勉強は苦しみました。。)
昨今TypeScryptと肩を並べてブームとなってきてる理由がわかるような気がしました

これからもちょこちょこGoをかじってみたいと思います!

ちなみに

やっている中でPHPでミスってる部分に気づかず、ちゃんと期待値通りの結果にならなかった時に思ったこと

PHPで$maxTableCountと書いている変数名、最初は$maxTableだけでCountをつけていませんでした(Goの方でmaxTableCountと書いていた別の日の自分がいたので、後日合わせた)

ですが、forの方の$maxTableを変えておらず、正常処理になってなかったのですが、普通に時間とメモリ量が出てきて、goよりも圧倒的に速く終わり、「え!なぜ???」というしょうもない調査時間がかかってしまいました。

その時に思ったことが以下。
TDDって大事だな〜
変数名をいったん適当にしてしまうことほど愚かなことないな〜

でした。これは本業に活かしていきます!!(●´ω`●)ゞ

ちなみにGoで同じようなミスをすると、、、

$ go run sample_1.go
# command-line-arguments
./sample_1.go:42:19: undefined: maxTable

なんとどこでどう間違ってるかを教えてくれちゃいます!!(これはとっても助かった!)
しかも、エラったところで止まるのではなく、コード全部検証して全部エラー出してくれます。
最初なんてこんな感じでしたw

$ go run sample.go
# command-line-arguments
./sample.go:21:2: too many arguments to return
    have (*status)
    want ()
./sample.go:31:11: undefined: GetStatus
./sample.go:33:23: status.Alloc undefined (type status has no field or method Alloc)
./sample.go:34:11: undefined: GetStatus
./sample.go:35:23: status.Alloc undefined (type status has no field or method Alloc)

テストを書かずして、ここまでエラー吐いてくれるのはすごく助かるっ!好き!ってなりました。

以上です!

参考

runtime.MemStatsでメモリ使用量を調べる&pprofモジュール
http://imagawa.hatenadiary.jp/entry/2016/12/22/190000

Goで時刻を取り扱う
https://qiita.com/taizo/items/acbee530bd33c803dab4

golangでかかった処理時間を計算するには?
https://kwmt27.net/index.php/2012/07/06/golangでかかった処理時間を計算するには/

PHPとGoって何が違うの?LIGが自社サービス開発にGo言語を採用したお話
https://liginc.co.jp/284306

Benchmarks: Node.js vs Go (vs PHP)
https://jaxbot.me/articles/benchmarks_nodejs_vs_go_vs_php_3_14_2013


『 Go 』Article List
Category List

Eye Catch Image
Read More

Androidに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

AWSに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Bitcoinに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

CentOSに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

dockerに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

GitHubに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Goに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Javaに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

JavaScriptに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Laravelに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Pythonに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Rubyに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Scalaに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Swiftに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Unityに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Vue.jsに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Wordpressに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

機械学習に関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。