Play2の公式サイトのWebSocketの解説を読んでいるとConcurrent.broadcastとConcurrent.unicastが出てきますよね。あまり詳しく書かれてなくて、良くわかんないので、ちょっとだけ自分でイジってみました。
その前にまずは、IterateeとEnumeratorを簡単に復讐しておきます。Iterateeとは、何かしらの入力が与えられたときに行う処理を保持しているものでした。例えば、入力を足し上げていく処理は、次のように書けます。
1 |
そして、Enumeratorは、Iterateeに入力を与えるものでした。例えば、1から10までの数字をIterateeに入力するには、次のようにします。
1 2 | val result: Future[Int] = enum.run( iteratee ) |
結果は、Futureとして取得されます。
1 |
以上がIterateeとEnumratorです。
では、broadcastとunicastは、IterateeとEnumratorとどう関係しているのでしょうか?broadcastとunicastがやりたいことってのは、基本的には同じです。すなわち、Channelを介してEnumeratorに入力を与えることです。つまり、ChannelがEnumerateeに入力を与え、Enumerateeは、Iterateeに入力を与えるという関係になっているんです。
では、実際にbroadcastを使ってみましょう。次の例では、1から4までの数字をChannelを介してEnumeratorに与えている処理を書いてみました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | val (enum, channel) = Concurrent.broadcast[Int] // Iteratorを実行 val result = enum.run( Iteratee.fold[Int, Int](0) { (sum, x) => sum + x }) // Enumeratorに入力を与える channel.push( Input.El(1) ) channel.push( Input.El(2) ) channel.push( Input.El(3) ) channel.push( Input.El(4) ) // 入力終わり channel.end // 10が出力される println( Await.result( result, 5.second ) ) |
上記のコードを見てもらえばわかるように、broadcastを使えば、channel.pushでEnumeratorに後から入力を追加することができるんです。これが、broadcastとunicastに共通している特徴だと思います。
次に、unicastで同じことしてみましょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | val enum = Concurrent.unicast[Int] { channel => // Enumeratorに入力を与える channel.push( Input.El(1) ) channel.push( Input.El(2) ) channel.push( Input.El(3) ) channel.push( Input.El(4) ) channel.end } // Iteratorを実行 val result = enum.run( Iteratee.fold[Int, Int](0) { (sum, x) => sum + x }) // 10が出力される println( Await.result( result, 5.second ) ) |
broadcastとの違いは、unicastは、Enumeratorを返すけど、Channelは返さない点です。Channelを、みんなが使えないようにしているんですね。使えるスコープを限定してChannelを共有できないようにしています。これが違いです。おそらく名前の違いも、このことが由来なんではないでしょうか?
以上、broadcastとunicastの違いでした。
0 件のコメント:
コメントを投稿