Gauche > Archives > 2012/07/26

2012/07/26 03:27:26 UTCyamasushi
#
; producer ..... yield手続きを引数にもつ手続き
; consumer ..... ジェネレータを引数にもつ手続き
(define (producer-consumer producer consumer :key (queue-size 100))

  (define (make-producer mtq)
    (^ []
      (guard (e [else 
                  (print (standard-error-port) (ref e 'message) ) 
                  (enqueue/wait! mtq (eof-object)) ] )
        (producer (cut enqueue/wait! mtq <>))
        (enqueue/wait! mtq (eof-object))
        ) ) )

  (define (make-consumer mtq)
    (^ []
      (guard (e [else (print (standard-error-port) (ref e 'message) ) ]) 
        (consumer (generate (^(yield)
                              (let loop [(xc (dequeue/wait! mtq))]
                                (if (eof-object? xc)
                                  (yield (eof-object))
                                  (begin
                                    (yield xc)
                                    (loop (dequeue/wait! mtq) ) ) ) ) ) ) )
        ) ) )    

  (and-let* [ ( mtq (make-mtqueue :max-length queue-size))
             ( c (make-thread (make-consumer mtq ) ) )
             ( p (make-thread (make-producer mtq )))]
    (let [(tc (thread-start! c))
          (tp (thread-start! p)) ]
      (thread-join! tp)
      (thread-join! tc) ; <----consumerの値を返す 
      ) ) )
#
イテレータの反転をスレッドで書くと、プロデューサコンシューマに化けるんですね。
2012/07/26 03:49:47 UTCshiro
#
色々試してもらった後でなんですが、rfc.httpの方をshift/resetを使わない形に書き直しました。もっともcall-with-input-uriを実装するにあたってreceiverプロトコルそのものを変えてしまうかもしれません。
2012/07/26 04:42:41 UTCyamasushi
#
了解です。一連の試行錯誤で勉強になりました。
2012/07/26 04:51:34 UTCyamasushi
#
receiverプロトコルで不完全文字列が使われているのが意外な感じでしたが、不完全文字列はこれからも使われていくのでしょうか?
2012/07/26 05:19:11 UTCshiro
#
R7RSでbytevectorが入るので、今後徐々にbytevectorにシフトしてゆくかもしれません (Gaucheではおそらくu8vectorと同じものになるでしょうが)
2012/07/26 10:13:12 UTCyamasushi
#
長さが不定の不完全文字列(もしくはu8vector)のジェネレータから、末尾以外は長さが固定の不完全文字列(もしくはu8vector)のジェネレータに直す簡便な方法はあるんでしょうか?(今回の試行錯誤でひっかかったトコロを整理すると、こういうことが出来たらいいなと。)
2012/07/26 10:29:52 UTCshiro
#
入力も出力もバイト列ならそう難しくは無いですが (出力を完全な文字列にしたいとなると、validな文字になるかどうかのチェックが面倒)、バッファリングの部分がとってもstatefulであんまり綺麗にならないでしょう。効率を考えないなら ($ gmap ($ u8vector->string $ list->u8vector $) $ (cut gslices <> 8) $ gconcatenate $ gmap ($ x->generator $ string->u8vector $) $) とか。
2012/07/26 11:07:47 UTCyamasushi
#
考えてみると、<buffered-input-port>のfillの実装のことなので、問題はもう少し緩やかになって、指定サイズを超えるとそのサイズでsliceする(短いものはそのまま。)ということでした。
#
不完全文字、u8vector版の"slice"があれば、それをgmapしてgconcatenateしてしまうということができそうな気がします。
2012/07/26 11:13:11 UTCshiro
#
まあそうですが、<buffered-input-port>のfillが「ベクタに値を埋める」というインタフェースになってるのも含め、バイトベクタを取り回すところはわりと低レベルな書き方を想定してるんで、ジェネレータを組み合わせるような抽象的な書き方よりは素直に「必要な量になるまで値を受け取る→余った分はどっかに取っとく」としてしまった方が結局はわかりやすい気もします。
2012/07/26 11:14:19 UTCyamasushi
#
効率という点では(データ、開始インデクス、長さ)の三つ組のジェネレータを考えるということになりますか。
#
なるほど。
#
低レベルAPIのときは、それに応じた書き方をしたほうがいいわけですね。
2012/07/26 13:08:19 UTCkoguro
#
参考までに MacOSX 10.8 (Mountain Lion) + Xcode 4.4 の組み合わせで Gauche 0.9.3.3 のビルドは通るみたいですね。HEAD はまだ試してません。
#
あと、関係無いですけど、src/Makefile.in の中で config_threads.h を作る時の grep は "grep --no-filename" としておいたほうが安全じゃないでしょうか。環境変数で GREP_OPTIONS=--directories=recurse とかしていたりすると、ファイル名が入り込んでしまうので。
#
おっと、ビルドじゃなくて make check まで OK でした。