SlideShare a Scribd company logo
IOクラスの入出力メソッドについてcuzic2010/04/24第42回 Ruby/Rails 勉強会@関西
自己紹介cuzic「きゅーじっく」と読みます。×quzic × cusic「リファクタリング Ruby エディション」の読書会を計画しています。@ JR 尼崎駅徒歩2分(小田公民館)日程未定Kent Beck 著 最近 JavaScriptの勉強中関数が First-Class Object でいいね。2010/04/24第42回 Ruby/Rails 勉強会@関西
IO クラスみんな知っているよね?puts “Hello, World!”STDOUT や STDIN は IO のインスタンスopen(“/tmp/tempfile”) do |io| ~endファイル入出力だけでなく、ネットワーク処理などにも IO クラスを利用。2010/04/24第42回 Ruby/Rails 勉強会@関西
Ruby のIO はかしこいRuby のスレッドとうまく連携ブロックする IO#read/IO#writeは内部的にselect(2) を利用。上手に他のスレッドを実行高水準 IO と低水準  IO の両方が利用可能高水準IO : FILE構造体(stdio)を使う printf(3) や puts(3) 低水準IO : file descriptor を使う read(2) などエラーが生じると例外を raise。EAGAIN、EINTR、EWOULDBLOCK とか低レベルのシステムコールも数多く利用可能fcntl (2) 、fsync (2) などに加え、BasicSocketではgetsockopt(2) や recv(2) なども利用可能2010/04/24第42回 Ruby/Rails 勉強会@関西
IO#read (1)IO#readlength長さを指定したいときはふつう これを使う。buffer = nilopen(“/dev/urandom”) do |io| buffer = io.read 10endp buffer#=> "\216X\222\300\217uT\236\232t"2010/04/24第42回 Ruby/Rails 勉強会@関西
IO#read (2)IO#readlength, buffer実は 第二引数を指定可能。事前にメモリ割り当てすることで高速化。require ‘benchmark’buffer = “ “ * 1000Benchmark.measure do   open(“/dev/zero”) do |io|1000_000.times do       io.read 1000, buffer   end  endend.display#=>  1.5000   0.0000   1.5000 (  1.3980)(比較) 58.8900   4.3440  63.2340 ( 62.6950)2010/04/24第42回 Ruby/Rails 勉強会@関西
IO#sysreadIO#sysreadは IO#readとどう違うの?IO#read は 受信バッファ を経由するIO#sysreadは 受信バッファ を経由しない受信バッファ って?IO はファイル以外にもいろいろ扱うネットワーク( TCP/UDP 等)とか欲しい length のデータがそろうまで、内部的にデータを貯めておいたり取り出されるのに先立って、データを保存しておいたり2010/04/24第42回 Ruby/Rails 勉強会@関西
受信バッファ受信バッファのおかげで詳細な入出力の処理を気にせず、プログラムを書ける
反面、ブロック(待ち)が発生してしまう。高速化の障壁になることも・・・。・待たずに別の処理をしたいのに・・・。・ある分だけでいいからすぐ欲しいのに・・・。2,000 Byte 欲しいなぁ。。。受信バッファ( 1,500Byte)パケット1000Byteパケット1000Byteまだないから、ちょっと待っとこっと。(ブロックの発生)
IO#readと IO#sysreadIO#readを使うと欲しい長さだけ取得可能IO#sysreadを使うと待ちが生じないr, w = IO.pipestr = "0123456789"Thread.startdow.writestr  sleep 10w.writestrendputs Time.now.strftime("%H:%M:%S")buffer = r.read 15# ここで、ブロック(待ちが発生)するputs Time.now.strftime("%H:%M:%S")puts buffer #=> “012345678901234”r, w = IO.pipestr = "0123456789"Thread.startdow.writestr  sleep 10w.writestrendputs Time.now.strftime("%H:%M:%S")buffer = r.sysread 15# すぐに次の行に移るputs Time.now.strftime("%H:%M:%S")puts buffer #=> “0123456789”
混ぜるな危険待ちをできるかぎり少なくしたいけど、、、IO#readと IO#sysreadは同時利用不可受信バッファの都合で、同時に使うとバグの元IO#gets、IO#each_lineなど、みんな IO#sysreadとは同時利用できません・・・。けど、どうしても同時に使いたい!!!そんなあなたに耳よりな話があります!!IO#read_nonblockIO#readpartial2010/04/24第42回 Ruby/Rails 勉強会@関西
IO#readpartialRuby 1.8.3 以降で利用可能受信バッファにデータがある場合は、とりにいかない
IO#readpartialIO#readpartialでは受信バッファに貯めることはしない
IO#read_nonblockRuby 1.8.5 以降で利用可能IO#readpartialと同様に IO#read等との同時利用が可能取り出せるものが何もないときは、例外が発生する何か取り出せるものがあれば、それを返す
各メソッドの動作IO#read (ブロッキングモード)確実にlength のデータを返す足りてなかったら、データの到着を待つIO#readpartial求める length のデータがそろってなくても、ある分だけ返す返すべきデータが何もなければブロックする。けど、なんかデータが到着したら、それを返す。IO#read_nonblock返すべきデータがなければ例外を raise する。ブロックしない。IO#sysread (ノンブロッキングモード)IO#read等と混用できない点を除いて、IO#read_nonblockと同じ動作どの Ruby でも問題なく動く。2010/04/24第42回 Ruby/Rails 勉強会@関西
細かい違いを整理する
いつ使うの?IO#readpartiallength取り出せるものが何かあれば取り出したいが、何もなければ、ブロックして欲しいときlength を大きな値として、ネットワークプログラミングなどで利用したり。IO#sysreadと違い、IO#read等と共存可能IO#read_nonblocklength一切ブロックさせずに IO を利用したい場合IO#sysreadと違い、IO#read等と共存可能IO#sysreadlength文字数がずっと短いIO#sysread使いこそが真の漢(?)。2010/04/24第42回 Ruby/Rails 勉強会@関西
具体的な利用例は?MongrelRuby で書かれた Web サーバ一部で readpartialを利用しているSecureRandomRuby 1.8.7 以降標準添付安全な乱数生成機/dev/urandomを readpartialで読み込み※ Unix 環境の場合EventMachine非同期サーバを作るフレームワーク一部で read_nonblockを利用している2010/04/24第42回 Ruby/Rails 勉強会@関西
まとめ「リファクタリング Ruby エディション」読書会を計画中Ruby の IO はかしこい低水準のことも高水準のこともできちゃうIO#readの第2引数は高速化に役立つこともある。IO#readpartialはネットワークプログラミングなどで重宝する
ご静聴ありがとうございました。

More Related Content

Ruby 勉強会 第42回 発表資料 IO について