Upload
shigeichiro-yamasaki
View
2.730
Download
3
Embed Size (px)
DESCRIPTION
Citation preview
Ruby1.9のFiberとクロージャのかっこいい使い方
Rubyist 九州山崎重一郎
まず、関数、クロージャ、継続の気持ちを説明してみます
マインドRuby ではどうなっているのか?
関数とマインド関数はいつも上から目線
自分自身の心が行っていることを幽体離脱して外から眺める感じ
ああしてこうしてこうなっ
たらこうして
関数の定義
0 マインド
「何もない」状態を考えてみましょう0 = φ = {}
{}
1 マインド
「何もない」と思っている自分を見ている自分 1 = {φ}
{}
2マインド
1 マインドの自分を見ている自分 2 = {φ,{φ}}
3マインド
2マインドの自分を見ている自分 3 = {φ,{φ},{φ,{φ}}}
ω マインド
これってずっと無限にできるよねと思っている自分 ω = {φ,{φ},{φ,{φ}},...}
... 「我は α であり ω である」 ヨハネの黙示録
ω+1 マインド
「これってずっと無限にできるよねと思っている自分」を見ている自分 ω+1 = {ω}
ω+ω マインド
ω マインドを対象にした対象化もまた無限にできるよねと思っている自分
• ω+1 = {ω,{ω},{ω,{ω}},...}
...
まだまだ
3ω マインドω×ω マインドωω マインド....
★ でも、ずっとずっとやると精神を病みます
ω マインドの関数定義λ を使うことが ω マインドの例
-> x { ... }階乗の再帰的定義fact = -> n {n==0 ? 1 : n*fact[n-1]}
★ 下のように書く方が Ruby っぽいけどfact = -> x {(1..x).reduce(:*)}
ω+ω マインドの関数定義λ を二つ使うと ω + ω
-> x { -> y {...} }
組み合わせ関数(再帰なのですっごく遅い)combi=->n{->r{r==1 ?n:(n==r ?1:combi[n-1][r-1]+combi[n-1][r])}}
でも有限のマインドも大切クロージャ:上から目線でつくった状態
ω マインドの視点から → nマインド(状態)を見る
ファイバー:継続、ジェネレータ
ジェネレータ: n マインドから ω マインドを見る その逆も
関数とクロージャ関数の独立変数と係数
f(x) = a*x
a は係数で x は独立変数?
係数の a を ω + ω の視点から見下ろして定義
fa= ->a {->x {a*x}}
で、 a に何かの値を束縛した ω な関数をつくる
fa= ->a {->x {a*x}}
> f=fa[2]> f[3]=> 6
> eval('a',f.binding)=> 2
関数のメモ化関数には時間の概念がないでも、もう一つ上の ω の視点から見おろせば状態が作れる
組み合わせ関数のメモ化combi_memo = ->m { ->n {m[n]||={}; ->r {m[n][r]||=combi[n][r]}}}
> cm=combi_memo[{}]
> cm[3][2]
=> 3
> cm[30][7]
=> 2035800
> eval('m',cm.binding)
=> {3=>{2=>3}, 30=>{7=>2035800}}
Fiber 継続、軽量スレッドFiber.new {|x|...}
ファイバーの生成
Fiver.yield(obj)親のコンテクストに行く
resume(obj) メソッド子供のコンテクストに行く(途中でとまっていた処理を継続)
f=Fiber.new {|x| puts ' 最初 ' Fiber.yield puts x y=Fiber.yield puts y }
> f.resume 3 #new メソッドへ最初=> nil> f.resume #yield メソッドへ3=> nil> f.resume 7 #yield メソッドへ7=> nil> f.resumeFiberError: dead fiber called
Fiber によるジェネレータn マインドと ω マインドを行き来する
無限ループでデータを無限に生成するプログラムの最初の n 要素
自然数ジェネレータ
num= -> a {loop {a+=1}}> num[0]
... 無限ループ〜
無限集合を素直に生成しているんだけどね
ファイバーにした自然数ジェネレータ
n = Fiber.new {|a|loop {Fiber.yield a+=1}}
無限集合の最初の 5 個だけ取り出す( Haskell みたいでかっこいい!)> 5.times {puts n.resume 0}12345=> 5
Fiber によるジェネレータフィボナッチ数列バージョン!フィボナッチ数列ジェネレータ
fib = -> x {a,b=x loop {a; a,b=b,a+b}}>fib[[0,1]]
... 無限ループ〜
フィボナッチ数列を素直に生成している
ファイバーにしたフィボナッチ数列ジェネレータ
f = Fiber.new {|x| a,b=x loop {Fiber.yield a; a,b=b,a+b}}
無限集合の最初の 5 個だけ取り出す> 5.times {puts f.resume [0,1]}01123=> 5
もっと Haskell チックにこんなのもいいかも!def f.take(n) n.times {puts self.resume} end> f.take 10
Fiber によるコルーチンで軽量イベント駆動マシン
初期の Macintosh OS多数のコルーチンの集合体でできていた(すっごく軽量なスレッドみたいなもの)
Macintosh 128K
8 MHz128Kbコルーチン
コルーチン
コルーチン
コルーチン
実際のメモリ
コルーチン
ビットマップへの表示など
操作によるイベント
Fiber によるコルーチンで軽量イベント駆動マシン
Rails 3.2 から Pjax が標準に
Web サーバに Fiber プールで軽量スレッドメモリ節約、起動/再起動の高速化
コルーチン
コルーチン
コルーチン
コルーチン
Fiber 対応 Web サーバunicorn とか Goliath とか
コルーチン
ブラウザへの表示変更
Pjax ブラウザ
操作によるイベント
Fiber と Thread の比較 出典: Ruby Fibers Vs Ruby Threads
http://oldmoe.blogspot.com/2008/08/ruby-fibers-vs-ruby-threads.html
Fiber によるリアルタイム処理
次回にね!