Ruby会議は2回目の参加になりますが、セッションの内容も変わらず濃いし色んな方にお話も聞けて幸せな時間でした!こちらの記事はカンファレンス中のいくつかのセッションのメモですー。
初日キーノート
MatzさんのRuby3で導入予定の型についてのお話!
最近の言語事情
2016年は静的な型言語がホット。静的言語と動的言語はお互いに影響を与えながら振り子のように進んでる。
Smalltalk -> Java -> Ruby/JS -> Swift/Go -> ?
その時々のトレンドに追随しても時代はすぐ進むのでRuby3では1歩先を目指してく。
Rubyにおける型
ダックタイピングにおける期待される振る舞いの集合のこと。
型に名前をつけるのは大変だし他言語のようにインタフェースを書いたりはしない。
(内部的な違いはマシン側で判断すればいい)
クラスによる型は制約が多すぎで、ダックタイピングは考えるコストを少なくできる。
動的言語の欠点
実行しないとエラーが分からない。
実行前のコンパイルでエラーがわかった方が便利。
型情報あればドキュメンテーションとして扱えていい。
(Rubyでもメソッドのコメントに型情報書いたりしてる)
型アノテーションや一部の型指定はあまり好ましくない。
ソフトタイピング(型推論)の導入
型はDRYじゃない、けどドキュメンテーションほしいし実行前エラーもわかった方が便利・・!
という矛盾を解決するため、静的型言語のようにエラーチェックができて、ダックタイピングできるものをRuby3では導入する予定。
100%の型チェックはできないけど80%は型推論できる。
-> a という変数が型推論で gsub, slice, map の振る舞いを期待されてる
-> ruby には存在しないクラス
-> エラーとして扱える
A proposal of new concurrency model for ruby 3
RubyのVM作者の笹田さんのRuby3で実装予定の新しい並列処理についてのお話。
マルチスレッドの難しさ
- レースコンディション(銀行口座の入出金の処理とか)
- デッドロック、ライブロック
- デバッグ(なかなか再現しなかったり)
全てのメソッドをスレッドセーフにしないといけない。
ロックを使って制御するとパフォーマンスの問題がでる。
Rubyではマルチスレッドによるパフォーマンスよりも、GVL(Global VM Lock)を使ってスレッドの切り替えとCのメソッド(Array#concatなど)を制御して、安全性/簡潔性を優先してきた。
新しい並列処理モデル Guild の導入
複数のスレッドを1つのグループにまとめたGuildの単位で並列処理を管理してく。
- 同じGuild内のスレッド同士は、現状通り同時には実行できない
- 別のGuildのスレッド同士は同時に実行できる
- 可変オブジェクトはいずれか1つのGuildに所属して、別Guildのオブジェクトへのread/witeは許可されない
- 定数やNumeric, true, false, nil などの不変オブジェクトは参照を別Guild同士で共有可能
Guild同士のコミュニケーション
Guild::Channelを使ってGuild同士でコミュニケーションとれるようにする。
コミュニケーションに使われるメソッドは2つ。
- Copy
- Transfer membership or Move in short
# オブジェクトのコピーを別Guildに送る
Guild::Channel#transfer(obj)
# オブジェクトを別Guildに送り、元のGuildへのオブジェクトのアクセスを禁止する
Guild::Channel#transfer_membership(obj)
Modern Black Mages Fighting in the Real World
Treasure Data @tagomoris さんの fluentd のバージョンアップのお話。
v0.14 アップデート
全部変えたよ!
- プラグインの名前空間(Fluent::* -> Fluent::Plugin::*)
- プラグインの共通クラス
- 一貫性のなかったOutputプラグインの階層構造
- 共通メソッドにてプラグインの
super
の呼び出しを必須に
v0.12 の問題点
APIのエントリーポイントのメソッドがプラグイン側の実装になってる。
- fluentd側で処理を挟むことができない(イベントのカウントなど)
- バージョンアップ時にメソッドをフックして互換性を保つとかできない
サードパーティのプラグインの実装によってメソッド呼び出しに一貫性がなくなってる。
- プラグイン作者がどう実装すべきか分かりづらい
- fluentdでどんなAPIのインタフェースがサポートされてるか分かりづらい
v0.14 のデザインポリシー
- fluentd側でAPIのエンドポイントを用意し、fluentd側のコントロールフローに従ってもらう(プラグイン側はデータフローなどをいじらず自身の実装のみする)
- プラグインのコールスタックをシンプル化
APIとコールスタックがシンプルに!
v0.12 と v0.14 の互換性の対応
v0.14
にアップデートしても v0.12
のプラグインが動く必要がある。
-
v0.14
でなくなったメソッドを補完するため、互換性レイヤーでプラグインのオブジェクトに対して、モジュールをMixinしてメソッドを差し込むことで対応 -
v0.14
でプラグインのライフサイクルの種類が増え(start,stop,shutdown,close…)、またこれらのメソッドはsuper
を呼ぶ必要があるため、プラグインのモジュールに対して、それらが呼ばれることを保証するためのモジュールをprependでMixinして対応
まとめ
fluentd は多くの黒魔術の上になりたってるよ!
SciRuby Machine Learning Current Status and Future
Rubyコミッター @mrkn さんのRubyの機械学習のお話。
Rubyで機械学習をやる
- 機械学習のアルゴリズムをRubyで書くということではない
- データサイエンスの仕事をRubyでやる
データサイエンスのワークフロー
- データを集める
- 探索的データ解析
- データクレンジング
- データの統合
- データの前処理
- 機械学習のモデルを構築
- 実世界に反映
これらのワークフローのうち機械学習の領域で、現状Rubyができてるところはなく、Pythonがこれらの領域をカバーしてるため、機械学習ではPythonが使われてる。
(言語の特性的にRubyが不向きでPythonが向いてるということではない)
機械学習を使う理由
実世界のデータに基づいてビジネス上の意思決定をできるようにしたい。
機械学習では人間が不可能な仕事ができ、解決法が分からない問題が解決できる。
(レコメンド、感情分析など)
教師あり学習
与えられたデータから一般的なルールを学習してく。
- 明日の天気の予測
- 明日の最高気温の期待値を予測
教師なし学習
データから本質的な構造を抽出。
- クラスター分析
- 主成分分析
(よくわかっていません。。)
強化学習
動的に変化する環境で意思決定のルールを学習していく。
- 将棋のAI
- 自動車の自動運転
SciRuby の現状
利用可能な機械学習ライブラリ
- liblinear-ruby.gem
- rb-libsvm.gem
- decisiontree.gem
実用的な機械学習システムの構築まではできてない。
(Python では scikit-learn というライブラリを作ってる)
実世界のデータ
- データの量が多すぎ、欠損値もあるため、データ全体を俯瞰して見ることができない。
- どのアルゴリズムが適するか判断できないため、複数のアルゴリズムを同時に試して、組み合わせる必要がある
scikit-learn とは
Scipy のための機械学習フレームワーク。
Python の機械学習のデファクトスタンダード。
SciRuby での機械学習の未来
- scikit-learn を ruby から使えるようにする
- ruby で同じようなライブラリを書く!(茨の道)
Optimizing Ruby
Rubyコミッター @shyouhei さんのRubyの最適化のお話。
ruby is slow!
ruby が遅いのは最適化されていないから。
1 + 2
というコードはアセンブラレベルでは3ステップくらいあり、初めから3
として最適化しておきたいけど、rubyではコードの実行中にメソッドの再定義ができるため、最適化せず実行してる。
最適化してから実行する
メソッドの再定義などは一旦忘れて、もしコードの実行中にメソッドが再定義がされてたら、最適化したのを捨てて再度処理する。
定数のたたみ込みの最適化
定数の計算はコンパイル時に計算しておく。
send の最適化
最適化が可能なメソッドをpure
として最適化対象として扱う。
ローカルではない変数へのアクセス、yield やpure
でないメソッドを呼んでいる場合はpure
でない。
def m
@foo = self
end
def m
Time.now
end
def m
yield
end
def m
{ foo: :bar }
end
メソッドの pure 状態の判定
初期状態は不定(method_missing などpureかわからない場合があるため)
コードを実行してく中でpure
かどうか確定したらcall cache
に格納する。
(引数の評価は副作用がある場合があるので省略できない)
変数の代入を省略
明らかに不要な変数を省略する(代入しても1度も使われない変数など)。
ブロックによって参照されていないかチェック。
ベンチマーク
特定のケースによっては400倍の改善がみこまれ、それ以外のベンチマークも大方変わらないか、少し遅くなるくらい。