Upgrade to Pro — share decks privately, control downloads, hide ads and more …

GO TechTalk #21 並列処理をGo/Rust/Kotlin/Python/JSで解説!思想の違いを体感しよう

GO TechTalk #21 並列処理をGo/Rust/Kotlin/Python/JSで解説!思想の違いを体感しよう

■ 内容
・技術書典への取り組みの紹介 (森下) p. 7 ~
・並列処理の基本 (森下) p. 11 ~
・Go編「Go ルーチンで並列処理を実装しよう」(森下) p. 23 ~
・Python編「ちょっとしたデータ分析の並列化・ Python」(西川) p. 31 ~
・Rust編「Rustにおける並列処理」(鈴木) p. 44 ~
・JavaScript編「JavaScript の 非同期処理 Promise、async/await を理解する」(橘) p. 61 ~
・Kotlin編「並行処理・非同期処理のアプローチ Kotlin」(狩谷) p. 82 ~

■ YouTube
https://www.youtube.com/live/m-1Drlk2G8w?feature=share&t=172

■ connpass
https://jtx.connpass.com/event/289233/

GO Inc. dev

August 09, 2023
Tweet

More Decks by GO Inc. dev

Other Decks in Programming

Transcript

  1. © GO Inc.
    GO TechTalk #21
    並列処理を
    Go/Rust/Kotlin/Python/JSで解説!
    思想の違いを体感しよう
    2023/8/8

    View full-size slide

  2. © GO Inc. 3
    GO株式会社について
    CO2削減・タクシーEV化


    View full-size slide

  3. © GO Inc.
    タイムテーブル
    4
    19:00-19:05 オープニング
    19:05-20:05 ・技術書典への取り組みの紹介 (森下)
    ・並列処理の基本 (森下)
    ・Go編「Go ルーチンで並列処理を実装しよう」(森下)
    ・Python編「ちょっとしたデータ分析の並列化・ Python」(西川)
    ・Rust編「Rustにおける並列処理」(鈴木)
    ・JavaScript編「JavaScript の 非同期処理 Promise、async/await を理解する」(橘)
    ・Kotlin編「並行処理・非同期処理のアプローチ Kotlin」(狩谷)
    20:05-20:10 クロージング
    20:10 終了

    View full-size slide

  4. 技術書典への取り組みの紹介
    並列処理の基本
    Go編「Go ルーチンで並列処理を実装しよう」
    Atsushi Morimoto
    5

    View full-size slide

  5. © GO Inc. 6
    自己紹介
    GO株式会社
    AI技術開発部
    データプラットフォームグループ
    AI寄りのアーキテクト
    『Visual Studio Code実践ガイド』技術評論社
    技術書典 3 ~ 14 に新刊参加
    @74th
    Atsushi Morimoto

    View full-size slide

  6. © GO Inc.
    本題の前に
    GO Inc. 技術書典への参加
    01
    7

    View full-size slide

  7. © GO Inc.
    ● 年2回ペースで開催されている
    技術系同人誌即売会
    ● オフラインとオンラインイベントが併設
    ● 技術書典10 ~ 14 にて GO Inc. もスポンサー!
    ● 技術書典11 ~ 14 にて
    会社の有志サークルとして参加し
    今まで4冊もの書籍を配布。
    ※ GO Inc. は技術書典以外にも
      Droid Kaigi、iOSDC、Go Conference など
      多数協賛しています
    技術書典とは
    8

    View full-size slide

  8. © GO Inc.
    GO Inc. では社内に様々なサービスがあり、
    それぞれ適材適所のプログラミング言語で実装されています。
    それぞれの言語で、共通したテーマを解説したら面白いのでは?
    とテーマを定め有志で記事を執筆し、技術書典13で頒布しまし
    た。
    1. 並行処理・非同期処理のアプローチ
    …JS、Kotlin、Python、Rust
    2. グラフアルゴリズム…Rust、Python
    3. ロガーの組み方 …Go、Kotlin
    4. 型とDI の扱い …Go、Python
    特集『4テーマを GO Inc. が使う複数の言語で解説してみよう』
    WebAPI、タクシー車載アプリ、ユーザアプリ、AIドラレコ、
    事業者向け管理Webサイト、AIサービス、GISサービス、などなど
    9

    View full-size slide

  9. © GO Inc.
    ● 電子版無料にて、技術書典マーケットプレイスにて配布中
    https://techbookfest.org/organization/4925641218588672
    技術書典11 ~ 14 でサークル参加
    10

    View full-size slide

  10. © GO Inc.
    並列処理の基本
    02
    11

    View full-size slide

  11. © GO Inc. 12
    本題に入る前に以下を説明します。
    ● 処理の実行のしかた:「並列処理」と「並行処理」とは
    ● 処理の連携のしかた:「同期処理」と「非同期処理」とは
    ● OSでの実行の基本「プロセス」「スレッド」とは
    はじめに

    View full-size slide

  12. © GO Inc. 13
    ● 処理の実行のしかた:「並列処理」と「並行処理」とは
    ● 処理の連携のしかた:「同期処理」と「非同期処理」とは
    ● OSでの実行の基本「プロセス」「スレッド」とは
    並列処理の基本

    View full-size slide

  13. © GO Inc.
    例2: 2つのレーンを用意して 2人が同時に処理する
    例1: 2つのタスクのレーンを用意して
    時間で切り替えて処理する
    14
    複数の処理を同時に扱うこと。
    並行処理(Concurrent)とは
    Task1
    Task2
    Task1
    Task2
    Task1
    Task2
    Task1
    Task2
    2つの仕事がある時
    シゴトシテ

    View full-size slide

  14. © GO Inc. 15
    複数の処理を扱えず、前の処理が終わってからしか、次の処理を与えられない。
    間髪入れず、次の処理を与えないと、何もしない時間(アイドル時間)ができる。
    並行処理(Concurrent)ではない
    タスク1
    シゴトシテ
    オケ
    Task1
    タスク2モ
    アルヨ
    ムリ
    ソロソロ
    ヤッテ
    オケ
    ヒマ
    Task2
    タスク3モ
    アルヨ
    ムリ
    アイドル時間

    View full-size slide

  15. © GO Inc.
    並行処理 例2: 2つのレーンを用意して2人が同時に処理する
    16
    複数の処理を「同時に実行」すること。並行処理の方法の1つ。
    より、適切にタスクを与えないと、何もしない時間ができる。
    並列処理(Parallel)とは
    Task1
    Task2
    アイドル時間

    View full-size slide

  16. © GO Inc. 17
    ● 処理の実行のしかた:「並列処理」と「並行処理」とは
    ● 処理の連携のしかた:「同期処理」と「非同期処理」とは
    ● OSでの実行の基本「プロセス」「スレッド」とは
    並列処理の基本

    View full-size slide

  17. © GO Inc. 18
    同じ時間を共有して、メッセージをやりとりする方法。片方が処理する間に待機が発生する。
    同期処理によるメッセージ
    Work1
    Work1
    シゴトシテ
    オワッタ
    ヒマ
    Work2
    シゴトシテ
    オワッタ
    Work3
    ヒマ
    ヒマ
    ヒマ
    ヒマ
    Work2

    View full-size slide

  18. © GO Inc. 19
    メッセージを「溜めて」、処理する方式。
    非同期処理によるメッセージ
    Work1
    Work1
    シゴトシテ
    Work2
    オボエトク
    ヒマ
    Work2
    マダアッタ
    Work3 Work4
    ・Work2
    ・Work3 ・Work4
    Work5
    ・Work4
    ・Work5
    3ツマデネ
    イケル?
    Work3

    View full-size slide

  19. © GO Inc. 20
    ● 処理の実行のしかた:「並列処理」と「並行処理」とは
    ● 処理の連携のしかた:「同期処理」と「非同期処理」とは
    ● OSでの実行の基本「プロセス」「スレッド」とは
    並列処理の基本

    View full-size slide

  20. © GO Inc.
    Program
    Program
    メモリ
    21
    プログラムを起動すると、メモリ上に展開され、プロセスとしてOSで管理される。
    プロセス内は実行の単位としてスレッドを用意し、OSはスレッドごとにCPUに割り当てる。
    プロセスとスレッド
    プロセス1
    スレッド1A
    スレッド1B
    プロセス2
    スレッド2A
    スレッド2B
    起動
    プロセス3
    スレッド3A
    スレッド3B
    CPU
    コア1
    コア2
    スレッド3A
    スレッド2B
    起動 起動
    OS
    時間で
    割り当て

    View full-size slide

  21. © GO Inc. 22
    ● 複数の処理の扱い方
    ○ not並行処理 :終わってからでないと、次の処理を渡せない。
    ○ 並行処理 :複数の処理を同時に「扱う」こと。
    ○ 並列処理 :複数の処理を同時に「処理する」こと。
    ● 処理間の連携の仕方
    ○ 同期処理 :同じ時間を共有して、メッセージをやりとりする方法。
    ○ 非同期処理 :メッセージを「溜めて」、処理する方式。
    ● プロセスとスレッド
    ○ プログラムは、起動すると「プロセス」としてメモリに展開される。
    ○ プロセス内の処理は、複数の「スレッド」を立てることができる。
    ○ OSは、CPUの各コアにスレッドを割り当てて、実行される。
    まとめ

    View full-size slide

  22. © GO Inc.
    (lang)
    ※ 以後、会社をGO、言語を Go または と表記します
    03
    23

    View full-size slide

  23. © GO Inc.
    ● 独自の軽量スレッド「Goルーチン」と、
    Goルーチン同士の同期・非同期通信の仕組み「チャネル」が、
    構文 に含まれている(後ほど解説)。
    ● GoランタイムがOSのスレッドを隠蔽し、Goルーチンに時分割に割り当ててうごかす。
    割り当てのスケジューリングはGoランタイムに任されていて、指示できない。
    ○ つまり、Goルーチン = 並列処理 ではない
    ● Goルーチンは、スレッド管理よりも軽量なため、使い捨てがかなりできる。
    での並列・並行処理
    OSスレッド OSスレッド OSスレッド
    OSプロセス
    Go
    ルーチン
    Go
    ルーチン
    Go
    ルーチン
    Go
    ルーチン
    Go
    ルーチン
    Go
    ルーチン
    実装者に見えている世界
    Goランタイムの仕事
    24

    View full-size slide

  24. © GO Inc.
    ● go 関数( ) で実行。
    即時関数を使うと go func(){ }() にな
    る。
    ● 経験則では
    1ms 以上のタスクであれば
    逐次で起動しても
    大きなオーバーヘッドにならない。
    ● CPUを可能な限り使って、
    Goのランタイムが実行してくれる。
    ● ネットワーク通信などの処理でも、
    積極的にGoルーチン化する。
    Goルーチンの実行方法
    func ParallelFunc(requests []entity.Request) {
    for _, request := range requests {
    go func(request entity.Request) {
    // 処理
    fmt.Print(request)
    }(request)
    }
    }
    25
    例: 引数の配列の要素単位にGoルーチンを起動

    View full-size slide

  25. © GO Inc. 26
    ストリーミング処理にGoルーチンを使う
    ● 処理を段階に分けて、分割する。
    ● より高負荷な処理(デコード・整形処理)で、Goルーチンをたくさん起動しておき、
    並列数を増やして処理をする。
    ● では、Goルーチンの起動時以外に、
    このGoルーチン間のデータ渡しはどうすれば良いか?→次スライド
    Go
    ルーチン
    Go
    ルーチン
    Go
    ルーチン
    Go
    ルーチン
    Go
    ルーチン
    データ受信処理
    デコード・整形処理
    Go
    ルーチン
    Go
    ルーチン
    DB書込処理
    Data
    Data
    Data
    Data
    例:車両のGPS座標データをDBに取り込む処理

    View full-size slide

  26. © GO Inc.
    ● チャネルは FIFO バッファ
    ● 変数 <- チャネル名 で受け取り
    チャネル名 <- 変数 で受け渡す。
    ● 事前にGoルーチンを起動しおき、
    処理の入力・出力をチャネルにして、
    for ループさせたりする。
    ● バッファサイズを指定でき、
    “0”だと同期処理に、
    ”1以上”だと非同期処理になる。
    ストリーミング処理のデータ渡しに チャネル を使う
    Go
    ルーチン
    Go
    ルーチン
    Go
    ルーチン
    Go
    ルーチン
    Go
    ルーチン
    データ受信処理 デコード・整形処理
    Go
    ルーチン
    Go
    ルーチン
    DB書込処理
    チャネル チャネル
    27
    Data
    Data
    Data
    func Run(upstream <-chan *entity.Request,
    downStream chan<- *entity.Request) {
    for i := 0; i < 64; i++ {
    go func() {
    for {
    // チャネルから受け取り
    request, ok := <-upstream
    if !ok {
    return
    }
    // 処理
    fmt.Print(request)
    // 次のチャネルへ流す
    downStream <- request
    }
    }()
    }
    }

    View full-size slide

  27. © GO Inc. 28
    チャネルの実行イメージ
    Go
    ルーチン
    Go
    ルーチン
    Go
    ルーチン
    Go
    ルーチン
    データ受信処理
    デコード・整形処理
    Go
    ルーチン
    Go
    ルーチン
    DB書込処理
    チャネルA
    チャネルB
    Data Data Data
    1.
    データ送信側は
    チャネルにデータを入れる。
    入れたら即座に、
    次のデータを処理する。
    Data
    2.
    次の処理の各GoルーチンはチャネルAから
    データを1つ取り出して処理する。
    チャネルAが空なければ待機する。
    3.
    処理を終えると、次のチャネルBにデータを渡し、
    再びチャネルAからデータを取り出す。
    Data
    4.
    また、処理の負荷によって、
    以下を調整する
    ・チャネルに入るデータの数
    ・Goルーチンの数
    Data

    View full-size slide

  28. © GO Inc.
    ● どこかが詰まっていて、期待するスループットが出ていないことがある。
    ● 一定時間毎に、チャネルの内容量をログ出力しておく。
    ● MAXサイズのチャネルがあると、その次の処理で詰まっていることがわかる。
    ○ 対処例1: 詰まっている処理のGoルーチンの数を更に増やす。
    通信処理の場合、相手先マイクロサービスで詰まってないか確認する。
    ○ 対処例2: CPUが100%ならば、プロセスの限界のため、
    プロセスのスケールアウト、スケールアップを検討する。
    Goルーチンと、チャネルでのトラブル
    Go
    ルーチン
    Go
    ルーチン
    Go
    ルーチン
    Go
    ルーチン
    Go
    ルーチン
    データ受信処理 デコード・整形処理
    Go
    ルーチン
    Go
    ルーチン
    DB書込処理
    チャネル チャネル
    29
    現在の内容量
    63/64
    現在の内容量
    1/64

    View full-size slide

  29. © GO Inc.
    ● 「Goルーチン」「チャネル」という、
    軽量スレッドと、軽量スレッド間通信バッファが 構文 レベルで提供されていて、
    すっきり記述できて良い。
    ● 経験上、Goルーチンは 1ms 以上の処理なら、1処理で逐次起動してもよい。
    (事前に起動しておいて、仕事に応じて割り当てることは実装しなくて良い)
    ● ストリーミング処理にはチャネルを使い、処理を部分的に並列に実行できる。
    ● チャネルの内容量をログ出力しておくと、ストリーミングで詰まってる処理がわかる。
    の並列処理のまとめ
    30

    View full-size slide

  30. Python編
    ちょっとしたデータ分析の並列化
    NISHIKAWA, Daisuke
    GO Inc.

    View full-size slide

  31. © GO Inc. 32
    自己紹介
    GO株式会社
    西川大亮(NISHIKAWA, Daisuke)
    2019年 DeNA AIシステム部にJOIN
    2020年 事業統合によりGOに転籍
    お客様探索ナビ(タクシー/ハイヤーの営業を効率化するサービス)の
    ● データサイエンティスト
    ● エンジニア(バックエンド[Python/Go]とWeb[TypeScript])
    ● サービスマネージャ
    ● 渉外/サポート
    など色々担当
    Pythonはアドホックなデータ分析と定型のデータ加工でよく使います。

    View full-size slide

  32. © GO Inc. 33
    やりたいこと Python編
    ちょっとしたデータ分析の並列化
    3ヶ月 1週間
    特徴量 ラベル
    特徴量 ラベル
    特徴量 ラベル
    処理は同じだけど集計期間が違う
    →並列化したい
    訓練データ作成の並列化 †ラベル: 『GO』を使う、クーポンを使う、etc...
    ‡特徴量: デモグラ、利用実績、アプリ起動回数、etc...
    ▪ 過去3ヶ月のデータから向こう1週間を推論するデータセットを作りたい

    特徴量作成は試行錯誤するのでPythonで楽に作りたい
    ▪ 過去5年分作ると52x5で260回の繰り返しで遅い
    ▪ 繰り返しの所をPythonで並列化したい

    View full-size slide

  33. © GO Inc.
    ▪ 今回やりたいのは並列処理
    すごく端折って書くと:

    並行: 複数処理を1CPUで

    並列: 複数処理を複数CPUで
    ▪ 並行処理は通信などのIOバウンド
    な処理で有効

    IOウェイトではCPUを使わないため

    複数のS3ファイルをローカルに落と
    すタスクとか
    ▪ 数値計算などのCPUバウンドに並
    行処理は向かない

    CPUが空かない
    34
    並列処理≠並行処理 Python編
    ちょっとしたデータ分析の並列化
    IOバウンドなら並行処理でOK
    CPUバウンドだと並行処理は効果なし
    CPU
    IO download #1
    download #2
    upload #1
    feature engineering #1
    feature engineering #2
    ※CPUは同時に1つしか
     使っていない
    CPU
    IO IO
    IO
    IO feature engineering #3
    ※CPUは同時に1つしか
     使えない
    ❌ こうならずに
    ⭕こうなる

    View full-size slide

  34. © GO Inc. 35
    Pythonは並列処理が苦手
    ▪ Global Interpreter Lock (GIL)

    プロセス内でバイトコードを実行できるスレッドは1つだけ

    CPythonのメモリ管理がスレッドセーフではないため

    初学者が詰まりやすい所をあらかじめ消している(とも言える)
    Java/Kotlin, Go と Pythonの並
    列化アーキテクチャの違い
    ▪ ではどうする?

    プロセスを分ける
    ▪ 別プロセス≒別アプリ
    ▪ 他の言語と全く違うアプローチ

    以降では標準モジュールの
    concurrent.futuresの
    ProcessPoolExecutorで解説
    Python編
    ちょっとしたデータ分析の並列化

    View full-size slide

  35. © GO Inc. 36
    並列処理の書き方
    ▪ funcが並列化したい関数
    ▪ ProcessPoolExecutorのsubmitに関
    数と関数に渡す引数を指定する
    ▪ 実行のたびに1,2,3の順番が変わ
    り、並列実行されている
    ▪ とっても簡単
    Python編
    ちょっとしたデータ分析の並列化
    from concurrent.futures import ProcessPoolExecutor
    from random import random
    from time import sleep
    def func(key):
    # keyを条件とする「ちょっとしたデータ分析」処理
    sleep(random())
    print(key)
    def do_parallel():
    with ProcessPoolExecutor() as executor:
    for key in [1, 2, 3]:
    executor.submit(func, key)
    if __name__ == '__main__':
    do_parallel()
    % python3 sample.py
    3
    2
    1
    % python3 sample.py
    2
    1
    3
    実行結果
    sample.py

    View full-size slide

  36. © GO Inc. 37
    プロセスの作られ方に癖がある
    ▪ Unix系OS

    forkシステムコールを呼ぶ(簡単!)
    ▪ macOS, Windows

    新規にプロセスを作り(spawn)

    Python処理系を起動

    submitを呼んだオブジェクトから到達可
    能なオブジェクトをpickle/unpickle†で
    転送
    Python編
    ちょっとしたデータ分析の並列化
    (落とし穴)pickle化できないオブジェクトが欠落する!
    ▪ ファイルオブジェクト
    ▪ DBコネクション
    ▪ S3クライアント
    ▪ lambda関数
    (copy on write)
    †Pythonが標準で提供するシリアライズ機構

    View full-size slide

  37. © GO Inc.
    ▪ 対話型インタプリタで動かない

    Jupyter(Lab/Notebook)が該当

    pickleはコード実体を保持せず、関数名を保持するため

    コード断片の実行順が不明なので新しいプロセスで再現できない

    これは対策がないので諦めて.pyで動くように書き直す
    ▪ submit時にpickle化できないオブジェクトがいると落ちる

    使っているライブラリ内のオブジェクトで落ちると辛い

    初期化をsubmitの後で行うように変更が必要

    lambdaもsubmitの後で作ればOK

    pickle化できるかをチェックするコードがあると良い
    38
    実装上の落とし穴 Python編
    ちょっとしたデータ分析の並列化

    View full-size slide

  38. © GO Inc. 39
    Pythonで並列処理を書く時のTips 1
    ▪ submit回数をコア数程度に絞る

    pickle化できない都合でsubmitの先で初期化するため
    ▪ 1000のタスクを2並列で行うなら
    ● submitを1000回呼ぶと初期化1000回
    ● 500のずつに分割してsubmitを2回呼ぶと初期化も2回
    ▪ 後段のデータ読み込みもまとめられるとなお良い

    初期化したいオブジェクトのキャッシュもあり
    ▪ とはいえリソース解放のタイミングが難しい
    Python編
    ちょっとしたデータ分析の並列化
    def do_parallel():
    with ProcessPoolExecutor() as executor:
    keys = list(range(1000))
    for key in keys:
    executor.submit(func, key)
    def do_parallel():
    with ProcessPoolExecutor() as executor:
    keys = list(range(1000))
    for key in [keys[:500], keys[500:]]:
    executor.submit(func, key)

    View full-size slide

  39. © GO Inc. 40
    Pythonで並列処理を書く時のTips 2
    ▪ データの読み書きをsubmitの先で行う

    pickle → プロセス間通信 → unpickleよりも都度読んだ方が速い
    ▪ キャッシュの効果が大きい
    ▪ 遅いNWを挟まない想定

    結果の戻しもそれぞれで書き出した方が速い
    ▪ データが少ない場合を除く
    ▪ 一貫性はRDBなど外部サービスで担保

    分割処理した結果は最後にまとめる必要がある

    項目が安定していてRDBに書き出せればデータ結合は楽
    Python編
    ちょっとしたデータ分析の並列化

    View full-size slide

  40. © GO Inc. 41
    Pythonでの並列化の設計方針
    ▪ CPUバウンドなら並列化が有効

    IOバウンドな処理は並行処理
    ▪ Pythonの並列処理実装が特殊であることを忘れない

    忘れると穴に落ちる
    ▪ pickle化できないオブジェクトに気を付ける

    コネクションなどは使う直前で作るようにする
    ▪ データの読み書きはサブプロセスで行う

    プロセス間通信を減らす(pickle/unpickleが重い)

    外部サービスが楽に使えればなお良い
    ▪ タスク数を無闇に増やさない

    初期化とデータ読み込みの効率化

    処理するCPU数ぐらいにタスクをグループにまとめる
    Python編
    ちょっとしたデータ分析の並列化

    View full-size slide

  41. © GO Inc.
    この資料の元ネタとなった技術書典13レビューにて:
    42
    おわりに
    …落とし穴とその回避方法を中心に紹介したので、こんな感想を持たれる方も
    多いかと思います。
     もちろん、メリットが大きいケースもあります(次スライド)
    面白く読めました。データ読み込みとかも個別プロセスで行うならば、複数プロセス
    化はPythonの外でしたほうがいいんじゃないか※とか思ってしまいました。
    ※強調は登壇者
    デスヨネー
    😭
    Python編
    ちょっとしたデータ分析の並列化
    監修者

    View full-size slide

  42. © GO Inc.
    Pythonで並列化するメリットが大きいケース
    ▪ データ分析のコードがPythonである
    ▪ 並列化するパートを試行錯誤したい
    ▪ ちょっとしたデータ分析である

    手元の端末で実行できるぐらいにシンプル

    CPU3桁必要とかメモリ4桁G必要とかではない

    バッチ処理であり応答性を求めない
    43
    おわりに
    Pythonでの並列処理は、優れた設計のシステムに後から†無理な要求を入れて
    しまい、色々と穴が開いてしまった事例だと思います。
    とはいえちょっとしたデータ分析には便利ですよ!
    Python編
    ちょっとしたデータ分析の並列化
    †バージョン 2.6 で追加

    View full-size slide

  43. Rustにおける並行処理
    Fumita Suzuki
    44

    View full-size slide

  44. © GO Inc. 45
    自己紹介
    プロフィール写真
    正方形にトリミングした写
    真を「図形に合わせてトリ
    ミング」で円形にすると真
    円になる
    GO株式会社
    エンジニア / Suzuki Fumita
    略歴 最初に入った受託系企業で官公庁のR&D案件を何回かやったのち、ス
    タートアップ業界に。2021年6月にGOに入社。現在はタクシー事業者向け
    の管理画面開発に注力。1児の父。趣味は船釣り。
    @maikii_chan

    View full-size slide

  45. © GO Inc.
    アジェンダ
    1. プロセスと並行・並列処理の基本
    2. スレッド間でデータ共有がない場合
    3. スレッド間でデータ共有がある場合
    4. Rustで並行処理を扱う際のメリット・デメリット
    5. 所感
    46

    View full-size slide

  46. © GO Inc.
    プロセス
    プロセス: コンピュータ上での計算を示す概念。下図のよう
    な状態遷移をする。
    時間
    t0 t1
    計算途中状態
    実行前状態 実行状態
    待機状態
    実行状態 実行終了状態
    47

    View full-size slide

  47. © GO Inc.
    並行性とは?
    時刻tにおいて、ある複数のプロセスが計算途中にあること
    時間
    t0
    t1
    並行実行中
    実行前状態 実行状態
    待機状態
    実行状態 終了状態
    実行前状態 実行状態
    待機状態
    実行状態 終了状態
    48

    View full-size slide

  48. © GO Inc.
    並列性とは?
    時刻tにおいて、ある複数のプロセスが実行状態にあること
    時間
    t0 t1
    並列実行中
    実行前状態 実行状態
    待機状態
    実行状態 終了状態
    実行前状態 実行状態
    待機状態
    実行状態 終了状態
    t2 t3
    並列実行中
    49

    View full-size slide

  49. © GO Inc.
    並行処理の何が難しいのか
    難しい問題の代表としてはプロセス間でのデータ共有。
    デッドロックなどが有名。
    デッドロック: プロセスやスレッドがお互いのリソースの解
    放を待ち続けそれぞれの処理が進行しなくなる状態。
    RDBMSなどで見聞きすることが多いかも
    50

    View full-size slide

  50. © GO Inc.
    データ共有がないパターンの並行処理
    use std::thread;
    use std::time::Duration;
    fn main() {
    // スレッド1を生成します。このスレッドは
    2秒間待ってからメッセージを表示します。
    let handle1 = thread::spawn(|| { // spawn()で新しいスレッドを立てる。
    thread::sleep(Duration::from_secs(2));
    println!("Hello from thread 1");
    });
    // スレッド2を生成します。このスレッドは
    1秒間待ってからメッセージを表示します。
    let handle2 = thread::spawn(|| {
    thread::sleep(Duration::from_secs(1));
    println!("Hello from thread 2");
    });
    // スレッド1が終了するのを待ちます。
    handle1.join().unwrap();
    // スレッド2が終了するのを待ちます。
    handle2.join().unwrap();
    // 実行結果
    // Hello from thread 2
    // Hello from thread 1
    }
    51
    データ共有がない場合は、
    スレッドを起動するだけ

    View full-size slide

  51. © GO Inc.
    データ共有があるパターンの並行処理
    Rustが標準ライブラリで提供しているチャネルを用いてス
    レッド間の通信を行うことができる。
    チャネル: スレッド安全なキューのようなもの。
    (スレッド安全: データ競合などの未定義動作を引き起こさないということ)
    52

    View full-size slide

  52. © GO Inc.
    チャネルの使い方
    use std::sync::mpsc;
    use std::thread;
    fn main() {
    // mpsc::channel()でチャネルを生成します
    (後述)
    let (sender, receiver) = mpsc::channel();
    thread::spawn(move || {
    let val = String::from("World!");
    // send()でチャネルにデータを送信します
    sender.send(val).unwrap();
    });
    // recv()でチャネルからデータを受信します
    let received = receiver.recv().unwrap();
    println!("Hello, {}", received); // Hello, World!
    }
    53

    View full-size slide

  53. © GO Inc.
    mpscクレートについて
    Rustではstd::mpscをインポートすることでチャネルを使う
    ことができる。multi-producer, single-consumerの略。
    以下の特徴がある。
    multi-producer
    sender(producer)を複数個作成することが可能。
    single-consumer
    receiver(consumer) は1個しか作成できない。
    54

    View full-size slide

  54. © GO Inc.
    receiverを複数作りたいとき
    mpscクレートだとreceiverが一つしか作れないため、困る事があ
    る。
     例:Webアプリサーバーでログへの書き込みが間に合わない
    receiverを複数作りたいときは、receiverをスレッド安全にして複数
    のスレッドからデータを読むようにする。
    スレッド安全にするために、MutexとArcを使う。
    55

    View full-size slide

  55. © GO Inc.
    Mutex, Arcについて
    std::sync::Mutex
    - 複数のスレッドからアクセスされると困るデータを保護
    するためにロックの仕組みを提供する。
    std::sync::Arc
    - 「Atomic Reference Count」の略。
    - 複数のスレッド間でデータを共有するための所有権を管
    理するための仕組みを提供する。
    MutexとArcは一緒に使うことが多い(気がする)。
    56

    View full-size slide

  56. © GO Inc.
    Mutex, Arcを使ってスレッド安全にreceiverを読む
    use std::sync::{mpsc, Arc, Mutex};
    use std::thread;
    fn main() {
    let (sender, receiver) = mpsc::channel();
    // Mutexを使ってreceiverをラップし、その MutexをArcでラップします。
    // これにより、 Mutexを複数のスレッドで共有できるようになります。
    let rx = Arc::new(Mutex::new(receiver));
    for i in 0..5 {
    // Arc::cloneを使って、rxの参照カウントを増やします。
    // これにより、複数のスレッドで rxを共有できます。
    let rx = Arc::clone(&rx);
    thread::spawn(move || {
    // ロックを獲得してチャネルからメッセージを受信します。
    // ロックはスコープを抜けると自動的に解放されます。
    let rx = rx.lock().unwrap();
    println!("thread {} received {}", i, rx.recv().unwrap());
    });
    }
    for i in 0..5 {
    // 5つのメッセージを送信します。
    // 各スレッドは 1つのメッセージを受信します。
    sender.send(i).unwrap();
    }
    }
    57
    Arc::new(Mutex::new(receiver))
    receiver値
    排他ロック
    アトミック参照カウント

    View full-size slide

  57. © GO Inc.
    Rustで並行処理を扱う際のメリデメ
    メリット
    - コンパイルが通った時点で安全性がかなり担保されてい

    - 安全性を確保しつつ、速度も最高レベル(ゼロコスト抽象
    化)
    デメリット
    - Arc(参照カウント)やMutex(ロック)など、幅広い知識が
    必要。
    58

    View full-size slide

  58. © GO Inc.
    所感
    - データ競合の問題をコンパイラレベルで弾けるのが便利
    -
    他の言語でデータ競合のバグが発生してしまった場合、再現や修
    正が大変になりがち。Rustの場合は発生可能性がある時はコンパ
    イルエラーになるので安心感がある。
    - 日本語のわかりやすい資料も増えてきて、学習コストは
    下がってきている。
    59

    View full-size slide

  59. © GO Inc.
    まとめ
    - プロセスと並行・並列処理の基本を説明した。
    - データを共有するときと共有しないときで、Rustの並行
    処理の書き方を説明した。
    - 標準のライブラリを単純に利用するだけでは実現できな
    い、複数スレッドでチャネルを読む方法を説明した。
    - Rustで並行処理を扱う際のメリット・デメリット、所感
    を発表した。
    60

    View full-size slide

  60. Confidential © GO Inc.
    JSの非同期処理のパターン
    Promise、async/awaitを理解する
    Yu Tachibana
    61

    View full-size slide

  61. © GO Inc. 62
    自己紹介
    プロフィール写真
    正方形にトリミングした写
    真を「図形に合わせてトリ
    ミング」で円形にすると真
    円になる
    GO株式会社 
    AI技術開発部 データプラットフォームG
    Yu Tachibana
    2015年5月  TomTom Japan入社
    2018年3月  DeNAオートモーティブ事業部に入社
    2020年4月〜 事業統合によりGOに転籍
    サーバーサイド開発、MLops周りの開発が多い(GCP、Python、Go)
    たまにWebアプリのフロントエンドも
    技術書典に5回出典
    @z_reactor

    View full-size slide

  62. © GO Inc.
    Confidential
    Webアプリでの非同期処理
    63

    View full-size slide

  63. © GO Inc.
    Confidential
    ● 本発表はブラウザー上で動くJSの話に絞る
    ● ブラウザ上Webアプリの世界は非同期処理まみれ
    ○ いつ来るか分からないイベント
    ○ いつ終わるか分からない通信
    Webアプリでの非同期処理について
    64

    View full-size slide

  64. © GO Inc.
    Confidential
    ● 私が業務上で開発した、→
    のようなユーザの入力と地図
    描画を同時にするようなWeb
    アプリでは、ますます非同期
    処理が必須となる
    ○ 地図はタイルごとに画像を読
    み込む必要があり、非同期で
    行われる
    Webアプリでの非同期処理の例
    65

    View full-size slide

  65. © GO Inc.
    Confidential
    ● 非同期処理が多いが、ブラウザ上のJSはシングルスレッドでしか動作し
    ない
    ● シングルスレッドで何も工夫しないと、データ待ちやイベント待ちなど
    で、画面が固まってしまう
    ● 擬似的な非同期処理で解決する
    ○ シングルスレッドの環境で、命令の呼び出しのタイミングを工
    夫し、無駄な待ち時間などを減らし、非同期処理として動いて
    いるかのように動作させる
    Webアプリでの非同期処理について
    66

    View full-size slide

  66. © GO Inc.
    Confidential
    console.log("A");
    setTimeout(() => {
    console.log("B");
    }, 100);
    Promise.resolve(C).then((res) => {
    console.log("D")
    });
    console.log("E");
    → 命令がPromiseのコールバック、setTimeout等のasyncコードの場合、
    Queueに投入し実行を遅らせることで擬似的非同期処理を実現している
    どうやって擬似的に非同期を実現しているか
    →call stack行き
    →queue行き
    →queue行き
    →call stack行き
    67
    ● ブラウザーのJS runtimeに主な構成要素が三つある
    ○ queue : 実行する命令を入れるFIFOの構造体
    ○ イベントループ : queueを常に監視し、Call Stackに命令を積む処理
    ○ Call stack : LIFO構造体。上にある命令から順番に実行される
    Call
    stack
    ソース
    コード
    イベント
    ループ
    queue
    パーサー&
    コンパイラー
    実行
    while (queue.waitForMessage()) {
    queue.processNextMessage();
    }

    View full-size slide

  67. © GO Inc.
    Confidential
    JS非同期処理の歴史と現在
    68

    View full-size slide

  68. © GO Inc.
    Confidential
    ● 標準化されていない非同期ライブラリで頑張る時代
    ● Promiseの登場
    ● async/awaitの登場
    JS非同期処理の歴史と現在
    69

    View full-size slide

  69. © GO Inc.
    Confidential 70
    ● ユーザーがWebページに求める機能性・利便性の向上に伴い、画面遷移
    せずに画面の一部を更新するAjax通信が必要となった。
    ● Ajax通信の実現には非同期処理が必要であり、様々な非同期ライブラリ
    が登場してきた。
    ● 非同期ライブラリは、非同期に呼び出す関数をコールバック関数として
    受け取っていました。
    標準化されていない非同期ライブラリで頑張る時代
    $("button").click(function(){
    $.get("http://xxxx/example.json",
    function(data, status){
    console.log("Data came with status:", data, status);
    }
    );
    });
    コールバック
    関数

    View full-size slide

  70. © GO Inc.
    Confidential
    つらみポイント
    ● コールバック地獄
    ○ コールバックを使った非同期関数を多くchainすると
    階層構造が深くなってしまう
    ● ライブラリによって書き方や引数の指定の仕方がまちまち
    ○ jQueryだと.done() と .fail()
    ○ axiosだと.then() と .catch()
    ○ 他にも.end()、.await()、.success() などなど
    標準化されていない非同期ライブラリで頑張る時代
    71

    View full-size slide

  71. © GO Inc.
    Confidential
    コールバック地獄
    72
    A(Aarg, (Ares) => {
    B(Ares.field, (Bres) => {
    C(Bres, (Cres) => {
    D(Cres, (Dres) => {
    console.log("結果:", Dres);
    })
    })
    })
    });
    ● とにかくネストが深い
    コードの説明
    Aの実行が終わったら、
    Bを非同期で実行し、終わったらCを
    非同期で実行し、終わったらDを非
    同期で実行し、終わったら
    console.logを実行する例

    View full-size slide

  72. © GO Inc.
    Confidential
    Promiseというのは?
    ● 非同期処理が終わった時に結果やエラーを返すためのJSのオブジェクト
    です
    ● 作成時にコンストラクター(Executor関数)にresolve, rejectのパラ
    メーターを渡す
    ○ resolve → 正常時の処理
    ○ reject → エラー処理
    ● 呼び出し時にthen, catchのinterfaceを呼ぶ
    ○ .then() → 正常に戻り値を返した後に行う処理を定義できる
    ○ .catch() → エラーを返した時に行う処理を定義できる
    Promise の登場
    73

    View full-size slide

  73. © GO Inc.
    Confidential
    A(Aarg, (Ares) => {
    B(Ares.field, (Bres) => {
    C(Bres, (Cres) => {
    D(Cres, (Dres) => {
    console.log("結果:", Dres);
    })
    })
    })
    });
    Promiseによるコールバック地獄の解消
    74
    → メソッドチェーンによりネ
    ストを深くすることなく、
    多段の非同期処理が記述でき
    るようになった
    A(Aarg)
    .then((Ares) => B(Ares.field))
    .then((Bres) => C(Bres))
    .then((Cres) => D(Cres))
    .then((Dres) => {
    console.log("結果:", Dres);
    });
    function A() {
    return new Promise((resolve, reject) => {
    const req = fetchData(url);
    if (req.status == 200) {
    resolve(req.data);
    } else {
    reject(new Error("Oops"));
    }
    });
    }

    View full-size slide

  74. © GO Inc.
    Confidential
    ● 共通のインターフェースに統一した
    ○ 正常終了は .then()
    ○ 異常終了は .catch()
    例:
    ○ エラーなどの処理が楽になった
    Promiseにより書き方がまちまちの解決
    75
    // callbacksだけで実現しようとするエラー処理
    A(Aarg, (err, Aarg) => {
    if (err) {
    // エラー処理
    } else {
    B(Aarg.field, (err, Ares) => {
    if (err) {
    // 別のエラー処理
    } else {
    // 以下略
    }
    })
    }
    });
    // 最後にcatchがあると、upstreamのどのPromiseでエラーが起きても
    catchできる
    A(Aarg)
    .then((Ares) => B(Ares.field))
    .then((Bres) => C(Bres))
    .then((Cres) => D(Cres))
    .then((Dres) => {
    console.log("結果:", Dres);
    });
    .catch((err) => console.log("Some Error happened", err.message));

    View full-size slide

  75. © GO Inc.
    Confidential
    そして、
    ● ES6以降、Promise がJSの標準仕様として装備された
    ● Promiseを使っている非同期ライブラリーが増えました
    → より読みやすい、書きやすい、分かりやすいコードに。嬉しい。
    Promiseが世の中で増える
    76

    View full-size slide

  76. © GO Inc.
    Confidential
      Promiseを更に分かりやすく・書きやすくした概念
    ● ES2017から、JSにasync/await構文が導入された
    ● Promiseのインターフェースが表に出なくてよくなった
    ● Promiseのsyntactic sugarである(裏側はバリバリPromise)
    ● そして導入後、色んなライブラリーがawaitに対応しました
    async/awaitの登場
    77

    View full-size slide

  77. © GO Inc.
    Confidential
    // async/await を使う関数の定義の仕方
    async function fetchData() {
    // 非同期処理その1
    const response = await fetch(url);  
    // 非同期処理その2
    const data = await response.json();  
    // dataを処理する
    }
    async/awaitの書きやすさその1:Promiseインターフェースの隠蔽
    // Promiseのままで処理すると
    function fetchData() {
    fetch(url).then(response => {
    return response.json();
    }).then(data => {
    // dataを処理する
    })
    }
    Before
    (Promiseだけを使った書き方)
    After
    (async/awaitを使った書き方)
    78
    → 見た目が同期処理っぽい書き方だから何が起きているか分かりやすい

    View full-size slide

  78. © GO Inc.
    Confidential
    ● 呼び出し側が下に下にまっすぐプログラムを書けるようになりました
    → try { } 、catch{ } などを使えば出来る
    ● Promiseの作成、then()や
    catch()が不要になった
    async/awaitの書きやすさその2:例外処理
    // async/awaitを使う関数のtry/catch処理
    async function fetchData() {
    try {
    const res = await fetch(url);
    // dataを処理する
    } catch (err) {
    throw new Error("my error")
    }
    }
    79

    View full-size slide

  79. © GO Inc.
    Confidential
    - Promise.all() が便利→複数のPromiseをチェインしやすい
    - asyncを使うことで、同期処理っぽく書けるため、コードが読みやすくなります
    - 最初からasync/awaitを使ってコードを書いていたから、コールバック地獄や
    Promiseの辛さを味わうことなく、平穏に暮らせています。先人に感謝♪
    発表者の所感
    Promise.all([
    getPolygons(), // Promiseを返す
    getMapTiles(), // Promiseを返す
    getStations(), // Promiseを返す
    ]).then((values) => {
    renderMapTiles(values[1]);
    processStations(values[2]);
    processPolygons(values[0]);
    })
    80

    View full-size slide

  80. © GO Inc.
    Confidential
    - 今日の話についてもっと詳しく読みたい場合: 是非 Tech It Up Vol.2を参照
    技術書典にもGOで出典しています
    81

    View full-size slide

  81. Kotlin の並行処理へのアプローチ
    Yohei Kariya

    View full-size slide

  82. © GO Inc. 83
    自己紹介
    GO株式会社
    IoT開発部 / 狩谷 洋平
    2018年4月 サーバーサイドエンジニアとして入社
    2020年1月 車載Androidアプリ開発チームへ異動
    現在は車載アプリの自動テストやデリバリー改善に注力

    View full-size slide

  83. © GO Inc. 84
    どうして並行処理が必要なの?
    ● Kotlin といえば Android アプリ
    ○ 例えば、ボタンをタップするとデバイ
    スとの接続状況を確認する機能
    ● GUIアプリケーションではUIス
    レッドで時間が掛かる処理をする
    と画面が固まる
    ● 待ち時間に別の処理を実行できる
    必要がある
    => 並行処理が必要
    button.onClickListener {
    showProgress()
    checkDevices() // <- 時間が掛かる
    hideProgress()
    }
    画面が固まって
    タップしても
    反応がない!!

    View full-size slide

  84. © GO Inc. 85
    どうやって並行処理をするの?
    ● Coroutineで並行処理を実現する
    ● launch {} ブロックで Coroutine
    を生成し、 Coroutine でブロック
    内に記述した処理を順次実行する
    ● 待ちが発生した Coroutine 以外の
    処理を実行できる
    button.onClickListener {
    showProgress()
    launch {
    checkDevices() // <- 時間が掛かる
    hideProgress()
    }
    }
    他の処理を実行できるため
    画面が固まらずタップすると
    反応がある!

    View full-size slide

  85. © GO Inc.
    ● Coroutine は OS が提供するスレッド(ネイティブスレッド)ではない
    ● Coroutine はただの Kotlin におけるオブジェクト
    ○ 一般的にグリーンスレッドと呼ばれるもの
    ● 1つのスレッドで複数の Coroutine を切り替えて実行できる
    86
    Coroutine はグリーンスレッド
    Coroutine A
    Coroutine B
    スレッド

    View full-size slide

  86. © GO Inc. 87
    Coroutine とスレッド
    Kotlin ランタイムが
    ● 複数の Coroutine から実行対象を選んでくれる
    ● 用途別のスレッドのまとまりが用意されていて、複数のスレッドから選び割
    り当ててくれる
    Coroutine
    Coroutine
    Coroutine
    Coroutine
    スレッド スレッド
    スレッド
    UIスレッド I/Oで使うスレッドのまとまり
    Coroutine
    Coroutine
    Kotlin

    View full-size slide

  87. © GO Inc. 88
    Coroutine とスレッド
    Kotlin ランタイムが
    ● 複数の Coroutine から実行対象を選んでくれる
    ● 用途別のスレッドのまとまりが用意されていて、複数のスレッドから選び割
    り当ててくれる
    プログラマーは
    ● 用途別のスレッドのまとまりを指
    定する
    ● スレッド1つ1つまでは意識しなく
    ていい
    button.onClickListener {
    showProgress()
    launch(Dispatchers.IO) {
    checkDevices() // <- 時間が掛かるので待つ
    hideProgress()
    }
    }
    前ページの「I/Oで使う
    スレッドのまとまり」

    View full-size slide

  88. © GO Inc. 89
    Coroutine の切り替え
    ● Coroutine の数がスレッドより多い場合は、スレッドに対して割り込む必要
    がある
    ○ UIスレッドは1つしかないので割り込めないと並行処理できない
    ● Go言語などでは実行系が強制的に割り込むが Kotlin では中断を明示的に宣
    言したタイミングでしか割り込まない
    Coroutine A
    Coroutine B
    スレッド 中断
    中断

    View full-size slide

  89. © GO Inc. 90
    中断の目印 suspend
    ● Kotlin の Coroutine において中断の目印は suspend というキーワードを付
    与したメソッドを呼び出したタイミング
    suspend fun b() {

    }

    View full-size slide

  90. © GO Inc. 91
    中断の目印 suspend
    ● Kotlin の Coroutine において中断の目印は suspend というキーワードを付
    与したメソッドを呼び出したタイミング
    ● コンパイラは Coroutine で実行し
    たい処理を中断できる処理に変換
    する
    launch {
    a()
    b()
    c()
    }
    fun invoke () {
    when (this.state) {
    0 -> {
    a()
    this.state = 1
    b()
    return …
    }
    1 -> {
    c()
    }
    }
    }
    変換イメージ
    ※あくまでイメージ
    suspend fun b() {

    }

    View full-size slide

  91. © GO Inc.
    ● Kotlin の Coroutine において中断の目印は suspend というキーワードを付
    与したメソッドを呼び出したタイミング
    92
    中断の目印 suspend
    Coroutine A
    Coroutine B
    suspend fun を呼んだ
    →中断
    suspend fun を呼んだ
    →中断
    再開
    suspend fun b() {

    }

    View full-size slide

  92. © GO Inc. 93
    Coroutine は親子関係を持てる
    ● launch { } 内で launch { } すると
    Coroutineが親子関係を持つ
    launch {
    launch {

    }
    launch {

    }
    }
    Coroutine
    Coroutine Coroutine

    View full-size slide

  93. © GO Inc. 94
    Coroutine は親子関係を持てる
    ● launch { } 内で launch { } すると
    Coroutineが親子関係を持つ
    ● 実は launch は CoroutineScope の
    メソッド
    coroutineScope.launch {
    launch {

    }
    launch {

    }
    }
    Coroutine
    Coroutine Coroutine
    Coroutine
    Scope

    View full-size slide

  94. © GO Inc. 95
    Coroutine は親子関係を持てる
    ● launch { } 内で launch { } すると
    Coroutineが親子関係を持つ
    ● 実は launch は CoroutineScope の
    メソッド
    ● launch { } ブロック内では this が
    親 Coroutineの CoroutineScope
    になる
    ( this. は省略可能)
    coroutineScope.launch {
    this.launch {

    }
    this.launch {

    }
    }
    Coroutine
    Coroutine Coroutine
    Coroutine
    Scope
    this

    View full-size slide

  95. © GO Inc. 96
    Coroutine を管理する CoroutineScope
    ● CoroutineScope で親子関係を持つ
    複数の Coroutine を管理する
    Coroutine
    Coroutine Coroutine
    Coroutine
    Scope

    View full-size slide

  96. © GO Inc. 97
    Coroutine を管理する CoroutineScope
    ● CoroutineScope で親子関係を持つ
    複数の Coroutine を管理する
    ● 例えば、どれか1つの Coroutine
    で例外が発生したら全ての
    Coroutine がキャンセルされるよ
    うにする
    Coroutine
    Coroutine Coroutine
    Coroutine
    Scope
    例外
    throw

    View full-size slide

  97. © GO Inc. 98
    Coroutine を管理する CoroutineScope
    ● CoroutineScope で親子関係を持つ
    複数の Coroutine を管理する
    ● 例えば、どれか1つの Coroutine
    で例外が発生したら全ての
    Coroutine がキャンセルされるよ
    うにする
    Coroutine
    Coroutine Coroutine
    Coroutine
    Scope
    例外
    throw
    cancel
    cancel

    View full-size slide

  98. © GO Inc. 99
    Coroutine を管理する CoroutineScope
    ● CoroutineScope で親子関係を持つ
    複数の Coroutine を管理する
    ● 例えば、どれか1つの Coroutine
    で例外が発生したら全ての
    Coroutine がキャンセルされるよ
    うにする
    ● Structured concurrency と呼ぶ
    Coroutine
    Coroutine Coroutine
    Coroutine
    Scope
    Coroutine が実行しっぱなし
    になることを防げる

    View full-size slide

  99. © GO Inc.
    10
    0
    CoroutineScope の例
    ● Androidでは標準ライブラリから提
    供される CoroutineScope がある
    ● 例えば、表示中の画面と紐づく
    CoroutineScope
    ○ 画面表示中はカーナビゲーションを更
    新し続ける
    ● 画面が切り替わったら Coroutine
    をキャンセルしてくれるので、実
    行しっぱなしにならない
    viewLifecycleOwner.lifecycleScope.launch {
    while (isActive) {
    updateNavigation()
    }
    }

    View full-size slide

  100. © GO Inc.
    10
    1
    まとめ
    ● Kotlin がスレッドに割り当てる Coroutine の切り替えをやってくれる
    ● プログラマーが Coroutine を程よく制御できる機能がある
    ○ Coroutine に割り当てて欲しいスレッドのまとまりを指定する
    ○ Coroutine を構造化してキャンセルの取り扱い方を決める
    ● 触れなかったけれど async や flow などコードの書きやすさ/読みやすさを上
    げるAPIが用意されている
    ● → Android アプリを実装しやすくすることにつながっているなぁと感じる

    View full-size slide

  101. © GO Inc. 102
    ⚫X(Twitter)アカウント
    技術全般 @goinc_techtalk
    AI関連 @goinc_ai_tech
    ⚫技術書典
    電子版を無料配布中!
    https://techbookfest.org/organization/4925641218588672
    Thank You!
    We Are Hiring!

    View full-size slide

  102. 文章・画像等の内容の無断転載及び複製等の行為はご遠慮ください。
    © GO Inc. 103

    View full-size slide