今週は第61回を開催しました!
引き続きKotlin Hands-onをすすめています。
前回の様子はコチラ↓
[第61回の様子]
2021/4/21に第61回を開催した。今週もいつもどおり水曜日開催。
参加メンバーは自分をいれて3名。本当はもう1人参加予定だったのだけれど急用でやむなく不参加に。
今回も自分がドライバ役で参加した。
勉強会本編の内容としては、ひき続きIntroduction to Coroutines and Channelsハンズオンを進めた。第7章 Showing progress
の最後の部分を読み、第8章Channels
のタスク直前までを読み込んだ。
[学んだことや疑問点]
- Introduction to Coroutines and Channels: 7. Showing progress
- タスクの答え合わせが終わり、最後の文章と図だけ残っていた
- この章の実装では、
updateResults()
が呼ばれるのが直列に実行されるリクエストの終わりだけで、並列処理になっていなかった - これを並列処理にして、中間結果を利用して
updateResults
を呼ぶにはどうすればよいだろうか? - 次の章で学ぶ、
Channnel
が解決してくれる - Introduction to Coroutines and Channels: 8. Channels
- 共有の可変の状態を使ってコーディングするのは難しく、間違いが起きやすい
- コミュニケーションによって情報を共有すればよい:coroutineの場合channnelを使う
- 複数のproducerがチャンネルに送信できるし、複数のconsumerがチャンネルから受信できる
- 注意:1つのメッセージはいずれかのconsumerに消費されるとチャンネルから削除される
- チャンネルはqueueのようなもの:違いは、send操作とreceive操作がsuspendされる点
- send時にチャンネル内のメッセージ上限に達している場合は待ちが発生する、receive時にはメッセージが空だと待ちが発生する
- チャンネルのインターフェースは次の通り
interface SendChannel<in E> { suspend fun send(element: E) fun close(): Boolean } interface ReceiveChannel<out E> { suspend fun receive(): E } interface Channel<E> : SendChannel<E>, ReceiveChannel<E>
- producerがclose()を呼び出すともうメッセージが来ない
- ライブラリで提供されているチャンネルにはいくつか種類がある
- 無制限チャンネル(Unlimited channel):queueと一番近い。メモリの許す限りメッセージを追加できる(ダメな場合OutOfMemoryException)。
- バッファチャンネル:メッセージの件数に上限がある。上限に達している場合、次のsend操作は中断される
- ランデブーチャンネル:保持できるメッセージの件数が0、すなわりsendとreceive操作がお互いを待ち続ける
- 合成チャンネル(conflated channel):新しいメッセージがくると古いメッセージが上書きされる。send操作はsuspendされない。
- チャンネルのインスタンス作成は以下のように行う
val rendezvousChannel = Channel<String>() val bufferedChannel = Channel<String>(10) val conflatedChannel = Channel<String>(CONFLATED) // Channel.CONFLATED val unlimitedChannel = Channel<String>(UNLIMITED) // Channel.UNLIMITED
- したがって、デフォルトではランデブー・チャンネルが作成される
- チャンネルを利用してメッセージをやりとりする例は以下の通り
import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.* fun main() = runBlocking<Unit> { val channel = Channel<String>() launch { channel.send("A1") channel.send("A2") log("A done") } launch { channel.send("B1") log("B done") } launch { repeat(3) { val x = channel.receive() log(x) } } } fun log(message: Any?) { println("[${Thread.currentThread().name}] $message") } // 出力結果は以下の通り // [main @coroutine#4] A1 // [main @coroutine#4] B1 // [main @coroutine#2] A done // [main @coroutine#3] B done // [main @coroutine#4] A2
- ランデブーチャンネルなのでA2より先にB1が送信されているのがわかる
- これを
Channel<String>(1)
のようにバッファチャンネルにすると出力が以下のようになる:A1のsendがsuspendされないのですぐにA2のメッセージが送信されている
[main @coroutine#4] A1 [main @coroutine#4] A2 [main @coroutine#4] B1 [main @coroutine#2] A done [main @coroutine#3] B done
[まとめ]
モブプログラミング・スタイルで、Introduction to Coroutines and Channelsハンズオンを進めた。
coroutineのチャンネルについて少し理解できた気がする!
今週はプルリクエストなし。