In article <87ad3l3kho.fsf / serein.a02.aist.go.jp>, Tanaka Akira <akr / m17n.org> writes: >>> 個人的には、欲しいのは stdio に協調して動く sysread です。stdio のバッ >>> ファにデータが溜ってる時には、sysread がそっちから読んでくれると嬉しい >>> ですね。sysread は即座に得られるデータがない時以外はブロックしないので、 >>> データがどうしても必要になってから sysread を呼べば、nonblock はだいた >>> い必要ないと思います。 この考えについてもう少し書きます。 > 即座に得られるデータが 1byte でもあれば partial read になるのでブロッ > クしないと理解しています。 > > 即座に得られるデータがない時以外にブロックすることってあるんですか? SUSv3 の read() の項を読む限り、ブロックするのは即座に得られるデータが 無い時だけです。 さて、現在の IO の読み込みメソッドは次のように nonblock に影響されます。 (他にあるでしょうか?) (1) 即座に得られるデータがある場合、read が即座に得られるデータだけを返す % (echo -n a; sleep 2; echo b)|ruby -rio/nonblock -e 'p STDIN.nonblock { STDIN.read(nil) }' "a" % (echo -n a; sleep 2; echo b)|ruby -rio/nonblock -e 'p STDIN.nonblock { STDIN.read(8) }' "a" (2) 即座に得られるデータがない場合、read(nil) が "" を返し、read(len) が EAGAIN を発生する % sleep 2|ruby -rio/nonblock -e 'p STDIN.nonblock { STDIN.read(8) }' -e:1:in `read': Resource temporarily unavailable (Errno::EAGAIN) from -e:1 from -e:1:in `nonblock' from -e:1 % sleep 2|ruby -rio/nonblock -e 'p STDIN.nonblock { STDIN.read(nil) }' "" (3) 即座に得られるデータが無い場合、eof? が即座に true を返す % sleep 2|ruby -rio/nonblock -e 't1 = Time.now; p STDIN.nonblock { STDIN.eof? }; t2 = Time.now; p t2-t1' true 0.000563 ここで、(1) は nonblock を使う目的です。少なくとも [ruby-talk:71562] [ruby-talk:87946] [ruby-list:24272] はそのような要求に思えます。 しかし、(2) は必ずしも適切な挙動ではありません。データが必要になった時 に read を呼ぶとすれば、データが 1byte 以上到着するまでブロックするの が適切でしょう。そうでなければ polling しなければいけないので面倒です し、下手に busy wait されたら迷惑です。また、理由はともかくどうしても ブロックしたくないのだとすれば、IO.select によってデータが到着している かどうか判定できますから、read を呼ぶ前に IO.select でデータの存在を確 認すれば、決してブロックしないという挙動は実現可能です。(race condition を気にしないことにすれば) 従って、この挙動は必須ではありませ ん。 また、(3) も IO.select を使えば、データがない時にブロックする eof? か らブロックしない eof? を作ることが可能です。従って、この挙動も必須では ありません。 というわけで、欲しいのは * 即座に得られるデータが存在する場合、ブロックせずに読み込む * 即座に得られるデータが存在しない場合、データが到着するまでブロックする というメソッドです。nonblock.rb のようなメソッドを組み込むよりは、こう いう用途に即したメソッドを付けるほうがいいと思います。 さて、そういうメソッドは、仮に readpartial という名前とすると、現在の Ruby では次のように実装できます。 class IO def readpartial(n) IO.select([self]) nonblock { STDIN.read(n) } end end しかし、実の所、この readpartial は stdio のバッファまわりの挙動を除け ば blocking-mode における sysread の挙動そのもので、実際、C レベルでは READ_DATA_PENDING とかを使えば nonblock を使わなくても実装可能なはずで す。 というわけで、readpartial を C レベルで追加すれば、nonblock の最大の問 題である他のプロセスへの影響も無くせて、その点でも嬉しいわけです。 ちなみに、readpartial という名前は partial read から思いついたわけです が、Nachos という教育用の OS に ReadPartial という関数があるようです。 他の名前の案としては、挙動は sysread そのものなので、sysread をそうし てしまうという方法が考えられます。readpartial と sysread の違いは stdio のバッファまわりで、sysread と他のメソッドを混用していないプログ ラムでは stdio のバッファは空なはずですから、その場合は readpartial と sysread の挙動は一致し互換性の問題はない、と思います。(その場合は本物 の read(2) を sysread! などとして用意すべきだとは思いますが) -- [田中 哲][たなか あきら][Tanaka Akira]