23
Ruby1.9 の Fiber ののののののの のののののののの Rubyist のの ののの

Ruby1.9のfiberのかっこいい使い方

Embed Size (px)

DESCRIPTION

 

Citation preview

Page 1: Ruby1.9のfiberのかっこいい使い方

Ruby1.9のFiberとクロージャのかっこいい使い方

Rubyist 九州山崎重一郎

Page 2: Ruby1.9のfiberのかっこいい使い方

まず、関数、クロージャ、継続の気持ちを説明してみます

マインドRuby ではどうなっているのか?

          

Page 3: Ruby1.9のfiberのかっこいい使い方

関数とマインド関数はいつも上から目線

 自分自身の心が行っていることを幽体離脱して外から眺める感じ

ああしてこうしてこうなっ

たらこうして

関数の定義

Page 4: Ruby1.9のfiberのかっこいい使い方

0 マインド

「何もない」状態を考えてみましょう0 = φ  =  {}

{}

Page 5: Ruby1.9のfiberのかっこいい使い方

1 マインド

「何もない」と思っている自分を見ている自分  1  =  {φ}

{}

Page 6: Ruby1.9のfiberのかっこいい使い方

2マインド

1 マインドの自分を見ている自分 2 =  {φ,{φ}}

Page 7: Ruby1.9のfiberのかっこいい使い方

3マインド

2マインドの自分を見ている自分 3 =  {φ,{φ},{φ,{φ}}}

Page 8: Ruby1.9のfiberのかっこいい使い方

ω マインド

これってずっと無限にできるよねと思っている自分  ω  =  {φ,{φ},{φ,{φ}},...}

... 「我は α であり ω である」     ヨハネの黙示録

Page 9: Ruby1.9のfiberのかっこいい使い方

ω+1 マインド

「これってずっと無限にできるよねと思っている自分」を見ている自分  ω+1  =  {ω}

Page 10: Ruby1.9のfiberのかっこいい使い方

ω+ω マインド

ω マインドを対象にした対象化もまた無限にできるよねと思っている自分

•   ω+1  =  {ω,{ω},{ω,{ω}},...}

...

Page 11: Ruby1.9のfiberのかっこいい使い方

まだまだ

3ω マインドω×ω マインドωω マインド....

★ でも、ずっとずっとやると精神を病みます

Page 12: Ruby1.9のfiberのかっこいい使い方

ω マインドの関数定義λ を使うことが ω マインドの例

-> x { ... }階乗の再帰的定義fact = -> n {n==0 ? 1 : n*fact[n-1]}

★ 下のように書く方が Ruby っぽいけどfact = -> x {(1..x).reduce(:*)}

Page 13: Ruby1.9のfiberのかっこいい使い方

ω+ω マインドの関数定義λ を二つ使うと ω + ω

-> x { -> y {...} }

組み合わせ関数(再帰なのですっごく遅い)combi=->n{->r{r==1 ?n:(n==r ?1:combi[n-1][r-1]+combi[n-1][r])}}

Page 14: Ruby1.9のfiberのかっこいい使い方

でも有限のマインドも大切クロージャ:上から目線でつくった状態

ω マインドの視点から → nマインド(状態)を見る

ファイバー:継続、ジェネレータ

ジェネレータ:  n マインドから  ω マインドを見る その逆も

Page 15: Ruby1.9のfiberのかっこいい使い方

関数とクロージャ関数の独立変数と係数

  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

Page 16: Ruby1.9のfiberのかっこいい使い方

関数のメモ化関数には時間の概念がないでも、もう一つ上の ω の視点から見おろせば状態が作れる

組み合わせ関数のメモ化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}}

Page 17: Ruby1.9のfiberのかっこいい使い方

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

Page 18: Ruby1.9のfiberのかっこいい使い方

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

Page 19: Ruby1.9のfiberのかっこいい使い方

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

Page 20: Ruby1.9のfiberのかっこいい使い方

Fiber によるコルーチンで軽量イベント駆動マシン

初期の Macintosh OS多数のコルーチンの集合体でできていた(すっごく軽量なスレッドみたいなもの)

Macintosh 128K

8 MHz128Kbコルーチン

コルーチン

コルーチン

コルーチン

実際のメモリ

コルーチン

ビットマップへの表示など

操作によるイベント

Page 21: Ruby1.9のfiberのかっこいい使い方

Fiber によるコルーチンで軽量イベント駆動マシン

Rails 3.2 から Pjax が標準に

Web サーバに Fiber プールで軽量スレッドメモリ節約、起動/再起動の高速化

コルーチン

コルーチン

コルーチン

コルーチン

Fiber 対応 Web サーバunicorn とか Goliath とか

コルーチン

ブラウザへの表示変更

Pjax ブラウザ

操作によるイベント

Page 22: Ruby1.9のfiberのかっこいい使い方

Fiber と Thread の比較 出典: Ruby Fibers Vs Ruby Threads

http://oldmoe.blogspot.com/2008/08/ruby-fibers-vs-ruby-threads.html

Page 23: Ruby1.9のfiberのかっこいい使い方

Fiber によるリアルタイム処理

次回にね!