kdnakt blog

hello there.

第62回Kotlin dojoを開催した

今週は第62回を開催しました!

引き続きKotlin Hands-onをすすめています。

 

前回の様子はコチラ↓ 

kdnakt.hatenablog.com

 

 

[第62回の様子]

2021/4/28に第62回を開催した。今週もいつもどおり水曜日開催。

だけどちょっとバタバタしていてブログの公開が遅れた。

 

参加メンバーは自分をいれて3名。

自分はナビゲータ役で参加してブツブツ言っていた。

 

勉強会本編の内容としては、ひき続きIntroduction to Coroutines and Channelsハンズオンを進めた。第8章Channelsのタスクを終わらせ、第9章Testing coroutinesの頭を少しだけ読んだ。

いよいよcoroutineハンズオンの終わりが見えてきたぞ!

 

[学んだことや疑問点]

  • Introduction to Coroutines and Channels: 8. Channels
    • チャンネルを通じた情報共有を実践するタスクに取り組む
    • loadContributorsChannels()関数を実装する
    • 過去に実装したloadContributorsConcurrent()関数と、loadContributorsProgress()関数を参考にしつつ、以下の大枠を利用する
val channel = Channel<List<User>>()
for (repo in repos) {
    launch {
        val users = ...
        // ...
        channel.send(users)
    }
}
repeat(repos.size) {
    val users = channel.receive()
    ...
}
    • 参考にした関数をはめこむをこうなる
// リポジトリ一覧取得部分をloadContributorsConcurrent()から移植
val repos = service
    .getOrgRepos(req.org)
    .also { logRepos(req, it) }
    .body() ?: listOf()

val channel = Channel<List<User>>()
for (repo in repos) {
    launch {
        // コントリビューター取得部分をloadContributorsProgress()から移植
        val users = service.getRepoContributors(req.org, repo.name)
                .also{ logUsers(repo, it)}
                .bodyList()
        channel.send(users)
    }
}
repeat(repos.size) {
    val users = channel.receive()
    ...
}
    • あとはreceive()した後の処理を実装するだけ。ここもloadContributorsProgress()を参考に実装すると以下のようになる
// 途中結果を保存するリストを作成
var allUsers = emptyList<User>()
repeat(repos.size) {
    val users = channel.receive()
    // 途中結果に集約
    allUsers = (allUsers + users).aggregate()
    // it(repeatのインデックス)とリポジトリ件数を比較して終了フラグ
    updateResults(allUsers, it == repos.size - 1)
}
    • 動作確認してみると、問題なく動いた。並列処理なので前回のものより数倍速い!
    • これは正解間違いなしでしょ、と思って模範解答を確認すると1箇所だけ差異が。
    • 終了フラグの取り方は、repos.lastIndexを利用するとスマートらしい。なるほど
    • 実際にCollection.ktのList<T>.lastIndexの実装を見てみると以下の様になっていた。そのまんまだけど便利そう。

f:id:kidani_a:20210429223754p:plain

repos request - returns an answer within 1000 ms delay
repo-1 - 1000 ms delay
repo-2 - 1200 ms delay
repo-3 - 800 ms delay

suspend関数だけを使った場合:4000ms = 1000 + (1000 + 1200 + 800)
並列処理を使った場合:2200ms = 1000 + max(1000 + 1200 + 800)
    • 時間がなかったので最初のところだけちらっと読んで終わり。

 

[まとめ]

モブプログラミング・スタイルで、Introduction to Coroutines and Channelsハンズオンを進めた。

Channelを使った処理の実装をして使い方も身についた!

 

今週のプルリクエストはこちら。

github.com