Posted at

What's Coming in Elixir 1.4

More than 1 year has passed since last update.

この記事はElixir (その2)とPhoenix Advent Calendar 2016 12日目の記事です。

Elixir 1.3のリリースからはや6ヶ月、Elixir v.1.1より大体6ヶ月ごとにマイナーリリースをしているようで、順調にいけば年明けにはv.1.4の正式版がリリースされそうです。

ということで来るべきElixir 1.4で新しく追加される機能の一部を紹介します。


Registry

v1.4で追加されたモジュールです。

公式の説明によると


The registry is a local, decentralized and scalable key-value process storage:


RegistryはKey-Value型で分散型のスケーラブルなローカルストレージです。



  • Local because keys and values are only accessible to the current node (opposite to distributed)


ローカルなので現在動作中のノードからのみアクセス出来ます。



  • Decentralized because there is no single entity responsible for managing the registry


Registryを管理する単一のエンティティが存在しないため分散しています



  • Scalable because performance scales linearly with the addition of more cores upon partitioning


パーティショニング時にコアが追加されるため、パフォーマンスが直線的に増加するためスケーラブルです


A registry is chosen upon start to have unique or duplicate keys. Every key-value pair is associated to the process registering the key. Keys are automatically removed once the owner process terminates.


一意のキーや重複するキーを持つようにレジストリが選択されました。すべてのキーと値のペアは、キーを登録するプロセスに関連付けられます。オーナープロセスがterminateされるとキーは自動的に削除されます。

iex> Registry.start_link(:unique, MyRegistry)

iex> {:ok, _} = Registry.register(MyRegistry, "hello", 1)
iex> Registry.lookup(MyRegistry, "hello")
[{self(), 1}]


With the registry, developers can provide dynamic process names, module-function dispatch or even a local pubsub system. See the Registry documentation for more information.


Registryによって動的なプロセス名や特定モジュールのfunctionをdipsatchしたりlocalなpubsubを実装出来ます。

とのことです。

ドキュメントにDispatcherやPubSubの説明の説明が書いてあったので参考に動かしてみます。


  • Dispatcher

/ # iex

Erlang/OTP 19 [erts-8.1] [source] [64-bit] [smp:4:4] [async-threads:10] [kernel-poll:false]

Interactive Elixir (1.4.0-rc.1) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> {:ok, _} = Registry.start_link(:duplicate, Registry.DispatcherTest)
{:ok, #PID<0.82.0>}
iex(2)> {:ok, _} = Registry.register(Registry.DispatcherTest, "hello", {IO, :inspect})
{:ok, #PID<0.83.0>}
iex(3)> Registry.dispatch(Registry.DispatcherTest, "hello", fn entries ->
...(3)> for {pid, {module, function}} <- entries, do: apply(module, function, [pid])
...(3)> end)
#PID<0.80.0>
:ok

apply/3を使ってhelloというtopicに対して登録されたプロセスでIO.inspectを実行しています。


  • local PubSub

/ # iex

Erlang/OTP 19 [erts-8.1] [source] [64-bit] [smp:4:4] [async-threads:10] [kernel-poll:false]

Interactive Elixir (1.4.0-rc.1) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> {:ok, _} = Registry.start_link(:duplicate, Registry.PubSubTest,
...(1)> partitions: System.schedulers_online)
{:ok, #PID<0.83.0>}
iex(2)> {:ok, _} = Registry.register(Registry.PubSubTest, "hello", [])
{:ok, #PID<0.85.0>}
iex(3)> Registry.dispatch(Registry.PubSubTest, "hello", fn entries ->
...(3)> for {pid, _} <- entries, do: send(pid, {:broadcast, "world"})
...(3)> end)
:ok

Registry経由で特定のトピック(hello)をsubscribeしてるプロセスに大して{:broadcast, "world"}というようなメッセージをsend/2でbroadcastしています。

Erlangでいうgprocのようなことが出来るModuleみたいです。gprocと同様にETSを使って実現し、ETSテーブルのshardingなどで性能を高めているそうです。

gprocと同様に複数のプロセスに同じ名前を付けたり一つのプロセスに複数の名前を登録出来るのでPubSubやDispatcherとしてEvent Handlingなど汎用的に使えます。

Elixirでgprocを使う例はあるけどインターフェースがErlangになるので標準でモジュールを提供してくれるのはありがたいですね。

Event HandlingするのにはGenEventというモジュールが既にあるけどGenEvent特有の問題もあるみたいで代わりとしてこれからRegistryを使っていけそうです。


Syntax coloring

ANSI Syntax Highrightがiexに来ました。

image

やっぱハイライトがつくとテンションがあがりますね。

他にも括弧にカーソルを合わせると対応する括弧がハイライトされたり細かい部分の挙動が改善されている印象でした。

Windowsでbabun上でTab Completionが効かなかったのもなんか直ってた…


Calendar

Elixir 1.3で追加されたCalendar型にday_of_week/3などが追加され強化されました。

iex(35)> Calendar.ISO.day_of_week(2016, 12, 12)

1


Task.async_stream

並行タスク処理の強化でTaskモジュールにasync_streamが追加されました。

今まではEnum出来るコレクションに対してはTask.asyncTask.awaitを使って以下のように処理していたのを

iex(1)> collection = [1, 2]

[1, 2]
iex(2)> collection \
...(2)> |> Enum.map(&Task.async(IO, :inspect, [&1])) \
...(2)> |> Enum.map(&Task.await/1)
1
2
[1, 2]

以下のように書くことが出来るようになりました

iex(1)> collection = [1, 2]

[1, 2]
iex(2)> collection \
...(2)> |> Task.async_stream(IO, :inspect, [], max_concurrency: System.schedulers_online) \
...(2)> |> Enum.to_list
2
1
[ok: 1, ok: 2]

Enumを受け取ってEnumを返しているので今までのasyncしてからawaitしていたより記述がわかりやすいですね。あとmax_concurrencyで最大並行数とか指定できます。


Application inference

mixのapplicationに明示的にdependencyを追加しなくても勝手にdependencyから検出してビルドしてくれるようになった(!)

これが

def application do

[applications: [:logger, :plug, :postgrex]]
end

def deps do
[{:plug, "~> 1.2"},
{:postgrex, "~> 1.0"}]
end

こう

def application do

[extra_applications: [:logger]]
end

def deps do
[{:plug, "~> 1.2"},
{:postgrex, "~> 1.0"}]
end

よくapplicationに追加したライブラリを書き忘れてno process errorになっていたりしたので地味にありがたいですね。

loggerなどランタイムで必要な一部のライブラリはextra_applicationsとして追加する必要はあるみたいです。

distilleryなどランタイムでは必要ないライブラリ(デプロイ、ビルド時のみに必要なもの)などはruntime: falseオプションで明示的にランタイムから外せるみたいです。

{:distillery, "> 0.0.0", runtime: false}


Mix install from SCM

escript(Elixirで書けるCLIツール)をmix経由でGitHubやhexから直接インストール出来るようになりました

例えばex_docを入れたい場合は以下のようにmix escript.install hex ex_docを叩くとHOMEディレクトリ以下の.mix/escriptsにバイナリがインストールされます

$ mix escript.install hex ex_doc

Running dependency resolution
Dependency resolution completed
earmark: 1.0.3
ex_doc: 0.14.5
* Getting ex_doc (Hex package)
Checking package (https://repo.hex.pm/tarballs/ex_doc-0.14.5.tar)
Fetched package
* Getting earmark (Hex package)
Checking package (https://repo.hex.pm/tarballs/earmark-1.0.3.tar)
Fetched package
==> earmark
Compiling 3 files (.erl)
Compiling 19 files (.ex)
warning: variable "option_related_help" does not exist and is being expanded to "option_related_help
()"
, please use parentheses to remove the ambiguity or change the variable name
lib/earmark/cli.ex:46

warning: variable "all_converters" does not exist and is being expanded to "all_converters()", pleas
e use parentheses to remove the ambiguity or change the variable name
lib/earmark/inline.ex:19

warning: variable "all_converters" does not exist and is being expanded to "all_converters()", pleas
e use parentheses to remove the ambiguity or change the variable name
lib/earmark/inline.ex:54

warning: variable "all_converters" does not exist and is being expanded to "all_converters()", pleas
e use parentheses to remove the ambiguity or change the variable name
lib/earmark/inline.ex:245

warning: module attribute @id_close_rgx was set but never used
lib/earmark/scanner.ex:9

Generated earmark app
==> ex_doc
Compiling 16 files (.ex)
Generated ex_doc app
Generated escript ex_doc with MIX_ENV=prod
Are you sure you want to install escript "ex_doc"? [Yn] y
* creating /root/.mix/escripts/ex_doc

warning: you must append "/root/.mix/escripts" to your PATH if you want to invoke escripts by name

簡単ですね。


まとめ

Elixir 1.4で導入された機能を一通り眺めてみた。

全体的に並行プラグラミングが強化されつつ細かい点も改善されたリリースになったんじゃないでしょうか。

細かい変更点はCHANGELOG.mdにあるのでそちらをご確認ください。

今すぐ試したい方はDockerHubに1.4.0-rc.1のイメージを上げておいたのでそちらで試してみてください

docker run -it --entrypoint sh shufo/phoenix:1.4.0-rc.1