next up previous contents
Next: 1.5.4 ディスパッチャ Up: 1.5 プロセス・ネットワーク Previous: 1.5.2 ストリームの連結

1.5.3 マージャ

前節で紹介した append を使うやり方には, ちょっと不満が残る. このやり 方では, ストリーム Squares の出力が終るまで, プロセス sum にはストリー ム Cubes に流れるメッセージがひとつも届かない. もし square の処理にか なり時間がかかるとすると, 並列に動いている sum は暇になってしまう. す でに cube の方の処理がある程度進んでいれば, その出力もどんどん足し込ん でいけるのに, メッセージが届かなくては何もできない.

そこで, 片方のストリームが終りまで来なくても, もう片方のストリームの出 力も中継してやれるようなやり方を考えよう. それには, どちらの入力スト リームにでも良いから, メッセージが来たらどんどん出力に流していくような プロセスを作れば良い. そのような述語の定義は以下のようになる.

merge([],In2,Out) :- Out=In2.
merge(In1,[],Out) :- Out=In1.
merge([Msg|In1],In2,Out) :- Out=[Msg|OutTail], merge(In1,In2,OutTail).
merge(In1,[Msg|In2],Out) :- Out=[Msg|OutTail], merge(In1,In2,OutTail).
最初のふたつの節は, どちらか一方のストリームが終りまで来たら, もう一方 のストリームをそのまま出力につないでしまえば良い, という意味である. 残りのふたつの節が, どちらか一方にメッセージが来た時にそれを中継して出 力する, ということをするためのものである.

このような, 複数のストリームからの入力すべてをひとつのストリームにまと めるプロセスを マージャ (merger) という. 前節に述べた append も マージャの一種ともいえるが, まず片方のストリームへのメッセージを流し, それが終ってからもう一方のストリーム, となっているので, より制限が強い.

  
図 1.6: マージャ

両方のストリームともにメッセージが来ている時に, この述語 merge がどの ような動作をするかに注目しよう. この場合, 3番目, 4番目の節は両方とも 適用条件を満たしている. このようなときにどちらが選ばれるかは, 言語仕 様としては決めていない. 同じプログラムを同じ入力データで動かしても, マージャが実際にどのように動くかによって, 流れていくメッセージの順番は 毎回違うかも知れない (図 1.6). これは KL1 の特質のひとつであ る非決定性が現れている例である.gif この非決定性はプログラムの デバッグには厄介な性質だが, この例のように並列性を上げるために必要な場 合がある. なお, 別々のストリームからのメッセージがどんな順で出力され るかは非決定的だが, もともと一本のストリームの中で前後関係があったメッ セージは出力中でもその前後関係を保っている.

この述語を使えば, 全体のプログラムは以下のようになる.

queer_sum(N,Sum) :-
    naturals(N,Naturals), square(Naturals,Squares), cube(Naturals,Cubes),
    merge(Squares,Cubes,Both), sum(Both,Sum).
これなら両方のストリームのどちらからでも, メッセージが来るごとにどんど んプロセス sum に送りつけることができ, 並列性の面で append を使ったプ ログラムよりも有利になっている. プロセスの全体像は図 1.7 に示 すようになっている.

  
図 1.7: マージャを用いたネットワーク

このように KL1 プログラムで定義するマージャでは, 入力の数を動的に増減 するなどの処理が容易でないこと, その際の効率を良くしにくいことなどの問 題がある. そこで, 入力ストリーム数を増減でき, 入力数の多寡にかかわら ず一定の手間でマージできるような, 組込機能としてのマージャも用意されて いる (ここでは詳しく述べない).



next up previous contents
Next: 1.5.4 ディスパッチャ Up: 1.5 プロセス・ネットワーク Previous: 1.5.2 ストリームの連結



KLIC