ErlangとGolangを比較してみる

# ErlangとGolangを比較してみる
よくこの2つの言語を比較する人がいるように感じる。
両方ともサーバープログラム用途で用いられる言語なので、分からなくもないのだが、この2つの言語は似て非なる物だ。

プロセス周りに重点を置いて違いについて自分なりに纏めてみた。

両方とも触れてから1年と経っていないので、間違いがあれば指摘をもらえると嬉しい。

## 主な違い
||Erlang|Golang|
|---:|:-----|:-----|
|言語の分類|関数型|手続き型|
|型|動的型付け<br /> (dialyzerによる型チェックあり) |静的型付け|
|変数|immutable | mutable |
|例外に関する思想|**Let it crash**|**Defensive Programming**|
|並行処理モデル|Message Passing <br /> (**Actor Model**)|Message Passing <br /> (**CSP/π caluculus**) |

## それぞれのプロセスの違い
||Erlang|Golang|
|---:|:---|:---|
|ワーカースレッド数|デフォルトでCPUのコア数|<del>デフォルトで1 <br /> (基本的にはCPUのコア数で指定)</del><br />[Go 1.5](https://golang.org/doc/go1.5)からデフォルトでCPUのコア数になりました|
|初期スタック|309 words <br /> (1words≒64bit) | 8k bytes|
|プロセス間メモリ共有|なし|あり (global変数)|
|プロセス数の上限|デフォルト 32768<br />最大 268435456|数10万可能|
|プロセスの実行|ワーカースレッドとバインドしない<br /> (固定することも可能)|ワーカースレッドとバインドしない|

※ プロセス = Erlang Process / goroutine

## 並行処理モデルの違い
この部分を書くのに、[arildさんのスライド](http://arild.github.io/csp-presentation/#)を参考にさせてもらった。
図が非常に分かりやすいので、こちらも参照して欲しい。

### Erlang: Actor model
- Process (Actor) が Mailboxを1つ持つ
 - 通信はどのProcessに送るかが明確
- ブロック
 - 受信側：Mailboxが空の場合ブロック
 - 送信側：ブロックしない
 
### Golang: CSP (Communication Sequential Processes)
- Channelを共有し、通信を行う
 - ChannelとProcessは多vs多の関係 (どのプロセスが受け取るか分からない)
- ブロック
 - 送信側と受信側が揃わないといけない

※ GolangはChannelサイズが指定できる為、サイズ>0の場合はChannelが空/満タンの場合にのみブロックする

## スケジューラー
大量にProcessを立てた場合、どのように実行されるかに違いがある。

- Erlang
 - 全てのProcessを均等に実行しようとする
- Golang
 - 一定時間までは1つ (コア数分) のProcessを実行し続ける<br />
 (ver1.2まではProcessがsleep/終了するまで実行し続けていた)

## プロセスの管理方法
### Erlang
- プロセスツリーを構成する

### Golang
- 管理しない
- 結果を待つことでデーモン化を防ぐ

## 例外処理
### Erlang
- 基本的な例外の扱い方
 1. 例外をcatchせずプロセス自体をクラッシュさせる
 2. スーパーバイザ（管理プロセス）がプロセスの異常終了を検知
 3. 再起動戦略に従ってプロセスを立ち上げ直す

```erlang:
-module(ch_sup).
-behavior(supervisor).

-export([start_link/0]).
-export([init/1]).

start_link() ->
    supervisor:start_link(ch_sup, []).

init(_Args) ->
    {ok, {{one_for_one, 1, 60},
          [{ch3, {ch3, start_link, []}, 
            permanent, brutal_kill, worker, [ch3]}]}}.
```
※ [公式の例](http://www.erlang.org/doc/design_principles/sup_princ.html)より引用


**再起動戦略**

||概要|
|:-----------|:----|
|one_for_one | 落ちたプロセスだけを再起動する|
|one_for_all | 全ての子プロセスを再起動する|
|rest_for_one | 子プロセスに依存関係がある場合に使用する |
|simple_one_for_one|子プロセスを動的に起動したい場合に使用する|

この辺りは[learn you some Erlang](http://www.ymotongpoo.com/works/lyse-ja/ja/20_wsts.html#id4)が詳しい

### Golang
- 関数の返り値としてerrorかどうかを返す
- エラーの処理を書かせるようになっている
 - 全ての変数はunusedでコンパイル時にエラーが出る <br />
   (ブランク変数／再代入を行うと処理忘れしてもエラーが出ないが……)

```go
file, err := os.Open("hoge.txt")
if err != nil {
    log.Fatal(err)
    return
}
```

- 最悪の手段としてpanic (≒throw) / recover (≒catch) が提供されているが使用するべきではない

```go
defer func() {
    if r := recover(); r != nil {
        fmt.Println(r)
    }
}()
panic("panic")
```

**補足1: panic/recoverの用途**
recoverを標準ライブラリ内で使用している箇所について、[ruiu](http://qiita.com/ruiu)さんが[こちらの記事](http://qiita.com/ruiu/items/ff98ded599d97cf6646e)に書かれている

- 深いネストからトップレベル関数へ一気に戻る
- ランタイムエラーをcatchし、関数の返り値として返す
- プロセス全体が落ちないようにする為

要約すると上記3つの用途で使われているとのこと。

**補足2: goroutine内でのpanic**

- `panic`が発生すると全てのプロセスが終了する
- goroutine内の`panic`は他のprocessでは処理できない

```go
go func() {
    defer func() {
        if r := recover(); r != nil {
            fmt.Println(r)
        }
    }()
    // 処理
}()
```

## まとめ
Erlang/Golangをどんな時に選ぶとよいかについて個人的な考えをまとめる。

- Erlang
 - Processが独立している場合 (Read/Writeが同じI/Fにできない場合など)
 - 分散プログラムになる場合 (今回は触れていないが……)
 - Processを大量に同時に立てる場合 (echo Server)
 - Processを落としたくない場合
- Golang
 - 複数のProcessが1つのQueueを共有したい場合
 - 文字列処理/計算を扱う場合
 - Processが落ちた場合でもそのProcessを再起動する必要がない場合

あくまでも個人的な意見だが、少しでも参考になれば幸いだ。