394
354

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

ErlangとGolangを比較してみる

Last updated at Posted at 2014-12-04

ErlangとGolangを比較してみる

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

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

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

主な違い

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

それぞれのプロセスの違い

Erlang Golang
ワーカースレッド数 デフォルトでCPUのコア数 デフォルトで1
(基本的にはCPUのコア数で指定)

Go 1.5からデフォルトでCPUのコア数になりました
初期スタック 309 words
(1words≒64bit)
8k bytes
プロセス間メモリ共有 なし あり (global変数)
プロセス数の上限 デフォルト 32768
最大 268435456
数10万可能
プロセスの実行 ワーカースレッドとバインドしない
(固定することも可能)
ワーカースレッドとバインドしない

※ プロセス = Erlang Process / goroutine

並行処理モデルの違い

この部分を書くのに、arildさんのスライドを参考にさせてもらった。
図が非常に分かりやすいので、こちらも参照して欲しい。

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を実行し続ける

    (ver1.2まではProcessがsleep/終了するまで実行し続けていた)

プロセスの管理方法

Erlang

  • プロセスツリーを構成する

Golang

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

例外処理

Erlang

  • 基本的な例外の扱い方
  1. 例外をcatchせずプロセス自体をクラッシュさせる
  2. スーパーバイザ(管理プロセス)がプロセスの異常終了を検知
  3. 再起動戦略に従ってプロセスを立ち上げ直す
-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]}]}}.

公式の例より引用

再起動戦略

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

この辺りはlearn you some Erlangが詳しい

Golang

  • 関数の返り値としてerrorかどうかを返す
  • エラーの処理を書かせるようになっている
  • 全ての変数はunusedでコンパイル時にエラーが出る

    (ブランク変数/再代入を行うと処理忘れしてもエラーが出ないが……)
file, err := os.Open("hoge.txt")
if err != nil {
    log.Fatal(err)
    return
}
  • 最悪の手段としてpanic (≒throw) / recover (≒catch) が提供されているが使用するべきではない
defer func() {
    if r := recover(); r != nil {
        fmt.Println(r)
    }
}()
panic("panic")

補足1: panic/recoverの用途
recoverを標準ライブラリ内で使用している箇所について、ruiuさんがこちらの記事に書かれている

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

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

補足2: goroutine内でのpanic

  • panicが発生すると全てのプロセスが終了する
  • goroutine内のpanicは他のprocessでは処理できない
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を再起動する必要がない場合

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

394
354
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
394
354

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?