「ElixirからRustの関数をつかう → はやい」 では Erlang/Elixir からネイティブプログラムを呼び出す方法として以下の3つが紹介されています。
- Port Driver
- Port Linked-In Driver
- NIF (Native Implemented Function)
ざっくり VM の外(1)か内(2, 3)かという事ですが、実は外も2種類:プロセスが親子になる場合(1)とならない場合があります。詳細はこちら。
今回はそのならない場合:C Node を rust で書いてみました。
お題は元記事のものをコピペで使わせて頂きます。
0. 環境
os: darwin-15.6.0 / MacBook Air(Mid 2011)
erlang: 19.0(erl_interface: 3.9)/ kerl で野良ビルド
rust: 1.11.0 / homebrew版
src は https://github.com/tomaon/ei にあります。
1. epmd(Erlang Port Mapper Daemon)の起動
$ epmd -daemon
$ epmd -names
epmd: up and running on port 4369 with data:
erl が上げてくれますが、先に上げておきます。
2. C node の起動
$ cargo run --example cnode
local: V6([::1]:3456)
epmd : (3456, 5)
ノード名は "r1@localhost"、ポートは 3456 です(決め打ち)。
一応 epmd に登録されていることを確認します。
$ epmd -names
epmd: up and running on port 4369 with data:
name r1 at port 3456
3. calc_pi の実行
-module(cnode).
-export([calc_pi/2]).
calc_pi(N, NumThreads) ->
{any, 'r1@localhost'} ! {N, NumThreads},
receive
Any ->
Any
end.
クライアント側も決め打ちです。
$ cd examples
$ erl -sname e1 -proto_dist inet6_tcp
C node が IPv6 で上がっているのであわせます(重要)。
Eshell V8.0 (abort with ^G)
(e1@x)1> c(cnode).
{ok,pi}
(e1@x)2> timer:tc(cnode, calc_pi, [1000000000,10]).
{16735480,{ok,3.141592655589816}}
はや、くはないですね。なんせ非力なマシンなので。。
まとめ
C node はやるべき事が多すぎて辛いです(全然やれてないですが)。
Port Driver の方が幸せになれます、たぶん。
初めての rust、とにかく動いて良かった。