小林さん

ありがとうございます。
恥ずかしながら見えていませんでした。
# 大津さんが仰っていたのもこれだったのですね。

取り急ぎお礼まで。


--
[email protected] (pc/mobile)
mobile 090-1736-8716
@yuichirowada on twitter



2013/4/19 Koichi Kobayashi <[email protected]>

> 小林 (koichik) です.
>
> ともあれ (JW)、一つ目の課題について自分が
> 想定していた問題点を書いてみます。
>
> サンプルのコードは以下の構造を持っています。
>
> var s = fs.createReadStream(f).once('open', function () {
>   this.pipe(response);
> });
> fs.stat(f, function(err, stats) {
>   s.on('data', function(data) {
>   });
> });
>
> pipe() が使われていますが、その中では 'data'
> (v0.10 以降では 'readable') イベントのリスナが
> 登録されるので、それを表に出すと以下のように
> なります。
>
> var s = fs.createReadStream(f).once('open', function () {
>   //(1)
>   s.on('data', function(data) {
>     //(2)
>   });
> });
> fs.stat(f, function(err, stats) {
>   //(3)
>   s.on('data', function(data) {
>     //(4)
>   });
> });
>
> ここで、(1)->(2) および (3)->(4) はこの順序で
> 実行されますが、それぞれの間では順序の保証は
> ありません。
>
> そのため、もし fs.stat() に時間がかかると、
> (3) のところで 'data' リスナを登録するよりも
> 先に、最初の 'data' イベントが発生してしまう
> 可能性があります。
>
> その場合、始めの方のデータは (2) の 'data'
> リスナだけが受信し、(4) の 'data' リスナは
> それを取りこぼすことになってしまいます。
>
> これは現実的にはまず起きないとは思いますが、
> 似た状況は setTimeout() を作ることができます。
>
> var s = fs.createReadStream(f).once('open', function () {
>   this.pipe(response);
> });
> setTimeout(function() {
>   fs.stat(f, function(err, stats) {
>     s.on('data', function(data) {
>     });
>   });
> }, 1000); //時間は適当
>
>
> これが一つ目の課題として想定した問題点です。
>
>
> 回避策としては、pause()/resume() を使うのが
> 素直なやり方かと思います。
>
> var s = fs.createReadStream(f).once('open', function () {
>   this.pipe(response);
> });
> s.pause(); //一時停止
> fs.stat(f, function(err, stats) {
>   s.resume(); //再開
>   s.on('data', function(data) {
>   });
> });
>
> v0.8 以前の場合、pause() は「アドバイス的」な
> ものということになっていますが、fs.ReadStream は
> かなり初期から (たぶん v0.2 の頃から) 中断中は
> 'data' イベントを生成せずにバッファリングしてくれて
> いたのでこれで大丈夫。
>
> v0.10 以降で導入された Stream2 では pause() は
> 「アドバイス的」ではなくなったのでやっぱり
> 大丈夫、そして pause() を呼び出すと "oldMode" に
> 切り替わるので、後から 'data' リスナを追加しても
> 安心になります。
>
>
>
> On Wed, 17 Apr 2013 02:40:00 +0900, Koichi Kobayashi <
> [email protected]> wrote:
>
> > 小林 (koichik) です.
> >
> > なぜ初心者には見えない人達が盛り上がってるのか
> > 小一時間(ry
> >
> > ともあれ (JW)、翻訳書からのサンプルなので、
> > 時期的に原書が v0.10 に対応しているはずがなく、
> > ここでは Stream1 の話ということにした方が
> > いいんじゃないかと思いますけれど。
> >
> > > てことで、「fs.stat() も open イベント内部に押し込むと、意図した順序で処理してくれる。」てのが課題に対する私の解答。
> >
> > んー、自分が想定 (期待) したのと違う問題を
> > 解決しようとしてるようなw
> >
> > fs.stat() を 'open' イベントリスナの中に押し込むと、
> > fs.stat() のコールバックが呼び出されるタイミングは
> > 元のコードよりさらに遅くなりますよね。
> >
> > すると、キャッシュのバッファを埋めるための 'data'
> > イベントのリスナを登録するのもさらに遅くなりますね。
> > それで大丈夫でしょうか?
> >
> > たとえば極端な例として、
> >
> > var s = fs.createReadStream(f).once('open', function() {
> >   response.writeHead(200, headers);
> >   this.pipe(response);
> > });
> >
> > setTimeout(function() {
> >   s.on('data', function(buf) {...});
> > }, 10 * 1000); // 10 秒!!!!
> >
> > だったらどうでしょうか?
> > setTimeout() の中で登録した 'data' リスナは
> > 適切に呼び出されるでしょうか?
> >
> >
> > On Tue, 16 Apr 2013 08:11:48 +0900, Akitoshi Manabe <
> [email protected]> wrote:
> >
> > > 眞鍋です。
> > >
> > > スミマセン。誤解してました。
> > > 以下のファイルを書いて試したところ、fs.createReadStream だと
> > > readable イベントは発火しませんでした。
> > >
> > > ---- (ここから)
> > > var util = require('util');
> > > var fs = require('fs');
> > > var f = __filename;
> > >
> > > var s = fs.createReadStream(f, {bufferSize: 128 }); // default : 64 *
> 1024
> > > [byte]
> > > s.on( 'readable', function(){ util.puts( 'readable', arguments ) }
> );//発火せず
> > > s.on( 'open', function(){
> > >     util.puts( 'open', arguments )
> > >     // data イベントはopen後でも追加できる。
> > >     s.on('data', function( d ){ util.puts('DATA ', d) })
> > > } );
> > > s.on( 'error', function(){ util.puts( 'error', arguments ) } );
> > > s.on( 'close', function(){ util.puts( 'close', arguments ) } );
> > > ---- (ここまで)
> > >
> > > 実は、readable イベントに押し込めるのではないかと考えていましたが、
> > > 「data イベントは open 直後に実行されるハンドラ内に定義しても良い」と確認できます。
> > > てことで、「fs.stat() も open イベント内部に押し込むと、意図した順序で処理してくれる。」てのが課題に対する私の解答。
> > >
> > >
> > > Nodeを始めた頃「関数のネスト(ピラミッドとも)で書く特徴」に悩まされました。
> > > 理解が深まってくると、ピラミッドをフラットで見やすく書く為の
> > > 「フロー制御」を考えたくなると思います。
> > >
> > >
> > >
> > >
> > > 2013年4月16日 7:08 aporo4000 <[email protected]>:
> > >
> > > > 全然違うかもしれませんが、最初に読み込むバイト数を指定するとか!?ですか?
> > > >
> > > > 2013年4月16日火曜日 1時20分00秒 UTC+9 koichik:
> > > >>
> > > >> 小林 (koichik) です.
> > > >>
> > > >> 勝手に課題シリーズ第二弾w
> > > >> 前のメールでも書いたように、非同期 API では
> > > >>
> > > >> ...   //(1)
> > > >> foo(hoge, function(err) {
> > > >>   ... //(2)
> > > >> });
> > > >> ...   //(3)
> > > >>
> > > >> の場合の処理順は (1)->(3)->(2) となります。
> > > >>
> > > >> 問題のコードは HTTP を処理するリスナの中に
> > > >> あるので、
> > > >>
> > > >> http.createServer(function(req, res) {
> > > >>   ...   //(1)
> > > >>   foo(hoge, function(err) {
> > > >>     ... //(2)
> > > >>   });
> > > >>   ...   //(3)
> > > >> });
> > > >>
> > > >> となるわけですが、ここで二つの HTTP リクエスト、
> > > >> A と B がほとんど同時に (ただし A が先に) 到着した
> > > >> 場合の処理順を考えてみましょう。
> > > >>
> > > >> その場合は、
> > > >> A(1)->A(3)->A(2)->B(1)->B(3)->B(2) となる。。。
> > > >> 保証はなくて、
> > > >>
> > > >> A(1)->A(3)->B(1)->B(3)->A(2)->B(2) だったり
> > > >> A(1)->A(3)->B(1)->B(3)->B(2)->A(2) だったり
> > > >> する可能性もあります。
> > > >> リクエスト A に関する処理が全て完了してから
> > > >> リクエスト B の処理が開始されるとは限らない
> > > >> わけです。
> > > >>
> > > >> さて、問題のコードからキャッシュの処理に着目すると、
> > > >>
> > > >> http.createServer(function (request, response) {
> > > >>     //(1)
> > > >>     if(cache[f]) {
> > > >>         response.writeHead(200, headers);
> > > >>         response.end(cache[f].content);
> > > >>         return;
> > > >>     }
> > > >>
> > > >>     fs.stat(f, function(err, stats) {
> > > >>         //(2)
> > > >>         var bufferOffset = 0;
> > > >>         cache[f] = {content: new Buffer(stats.size)};
> > > >>         s.on('data', function(data) {
> > > >>            //(3)
> > > >>            data.copy(cache[f].content, bufferOffset);
> > > >>            bufferOffset += data.length;
> > > >>         });
> > > >>     });
> > > >> }).listen(8080);
> > > >>
> > > >> という構造を抽出できるのですが、最初に到着した
> > > >> リクエスト A の処理では、
> > > >>
> > > >> (1) キャッシュが存在しないことを確認し、
> > > >> (2) キャッシュを作成して fs.stat() を呼び出し、
> > > >> (3) 'data' イベントが発生するとキャッシュの中身を設定
> > > >>
> > > >> と流れていくことはもう理解できているかと思います。
> > > >>
> > > >> では、この途中のどこかで別のリクエスト B が到着すると
> > > >> どうなるでしょうか?
> > > >>
> > > >> A(1)->A(2)->A(3)
> > > >>
> > > >> と進む途中のどこかで、リクエスト B の処理が
> > > >> 挟まってきた場合を考えてみましょう。
> > > >>
> > > >> A(1)->B(1)->?
> > > >>
> > > >> とか、
> > > >>
> > > >> A(1)->A(2)->B(1)->?
> > > >>
> > > >> とか、タイミングによっては B の処理が進む経路も
> > > >> 変わってくるはずですね。
> > > >>
> > > >> 掲載されたコードはどんな場合でも正しく
> > > >> 動作するでしょうか?
> > > >> うまくいかないのはどんな場合?
> > > >> どんな場合でもうまく動くようにするに
> > > >> どうしたらいいでしょうか?
> > > >>
> > > >>
> > > >> On Mon, 15 Apr 2013 06:18:31 -0700 (PDT), aporo4000 <
> [email protected]>
> > > >> wrote:
> > > >>
> > > >> > いまちょうどそれを勉強してる初心者なので、みなさんみたいにスラスラ書いたり出来るように頑張ります!
> > > >> >
> > > >> > --
> > > >> >
> > > >> > ---
> > > >> > このメールは Google グループのグループ「Node.js 日本ユーザグループ」の登録者に送られています。
> > > >> > このグループから退会し、メールの受信を停止するには、[email protected]
> にメールを送信します。
> > > >> > その他のオプションについては、https://groups.google.com/groups/opt_outにアクセスしてください。
> > > >> >
> > > >>
> > > >>
> > > >> --
> > > >> {
> > > >>   name: "Koichi Kobayashi",
> > > >>   mail: "[email protected]",
> > > >>   blog: "http://d.hatena.ne.jp/koichik/";,
> > > >>   twitter: "@koichik"
> > > >> }
> > > >>
> > > >>  --
> > > >
> > > > ---
> > > > このメールは Google グループのグループ「Node.js 日本ユーザグループ」の登録者に送られています。
> > > > このグループから退会し、メールの受信を停止するには、[email protected]
> にメールを送信します。
> > > > その他のオプションについては、https://groups.google.com/groups/opt_out にアクセスしてください。
> > > >
> > > >
> > > >
> > >
> > > --
> > >
> > > ---
> > > このメールは Google グループのグループ「Node.js 日本ユーザグループ」の登録者に送られています。
> > > このグループから退会し、メールの受信を停止するには、[email protected]にメールを送信します。
> > > その他のオプションについては、https://groups.google.com/groups/opt_out にアクセスしてください。
> > >
> > >
> >
> >
> > --
> > {
> >   name: "Koichi Kobayashi",
> >   mail: "[email protected]",
> >   blog: "http://d.hatena.ne.jp/koichik/";,
> >   twitter: "@koichik"
> > }
> >
> > --
> >
> > ---
> > このメールは Google グループのグループ「Node.js 日本ユーザグループ」の登録者に送られています。
> > このグループから退会し、メールの受信を停止するには、[email protected]にメールを送信します。
> > その他のオプションについては、https://groups.google.com/groups/opt_out にアクセスしてください。
> >
>
>
> --
> {
>   name: "Koichi Kobayashi",
>   mail: "[email protected]",
>   blog: "http://d.hatena.ne.jp/koichik/";,
>   twitter: "@koichik"
> }
>
> --
>
> ---
> このメールは Google グループのグループ「Node.js 日本ユーザグループ」の登録者に送られています。
> このグループから退会し、メールの受信を停止するには、[email protected]にメールを送信します。
> その他のオプションについては、https://groups.google.com/groups/opt_out にアクセスしてください。
>
>
>

-- 

--- 
このメールは Google グループのグループ「Node.js 日本ユーザグループ」の登録者に送られています。
このグループから退会し、メールの受信を停止するには、[email protected] にメールを送信します。
その他のオプションについては、https://groups.google.com/groups/opt_out にアクセスしてください。


メールによる返信