0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Kotlin】launch × async / await × withContext の使い分け

Posted at

はじめに

Kotlin のコルーチンでは、非同期処理を簡潔に書ける3つの主要関数があります:

関数 戻り値 用途 結果の取得方法
launch Job 戻り値が不要な処理 .join()
async Deferred<T> 並列に計算・取得したい処理 .await()
withContext T スレッドを切り替えて順次実行 戻り値そのもの

それぞれ似ていますが、
「並行実行するか」「結果をどう扱うか」 が大きく違います。


1. launch ― 戻り値不要な非同期処理

launch「裏で動かしたいけど結果はいらない」 タスクを起動する。

import kotlinx.coroutines.*

fun main() = runBlocking {
    val job = launch {
        delay(1000)
        println("🌙 Launch Task Done!")
    }

    println("🌞 Main continues...")
    job.join() // 完了を待つ
}

ポイント:

  • 戻り値は Job
  • .join() で待機できる
  • 戻り値が不要な処理(UI更新・ログ送信など)に最適

2. async / await ― 結果を返す並行処理

async非同期で計算を開始し、結果を Deferred として返す。
await() でその結果を受け取る。

fun main() = runBlocking {
    val apple = async {
        delay(1000)
        "🍎 Apple"
    }
    val orange = async {
        delay(500)
        "🍊 Orange"
    }

    val result = "${apple.await()} & ${orange.await()}"
    println("完了 → $result")
}

ポイント:

  • 戻り値は Deferred<T>
  • .await() で結果を取得
  • 並列に実行可能
  • 戻り値が必要な処理(APIリクエスト・計算処理)に最適

3. withContext ― スレッド切り替えで順次処理

withContextスレッド(Dispatcher)を切り替えて処理を実行し、その結果を返す
他の処理と並行実行はしない

fun main() = runBlocking {
    val data = withContext(Dispatchers.IO) {
        delay(1000)
        " Loaded data"
    }

    println("結果: $data")
}

ポイント:

  • スレッドを安全に切り替える(例:MainIO
  • 戻り値を直接返す(T
  • 順次処理(直列)
  • 典型的には:UI→IO→UI の切り替え

4. 機能比較まとめ

比較項目 launch async / await withContext
戻り値 Job Deferred<T> T
結果の取得 .join() .await() 戻り値そのもの
並列実行 可能 可能 不可(順次)
用途 ログ・UI更新など 並列計算、複数API呼び出し スレッド切替、IO操作
Dispatcher指定
例外処理 try-catch で制御 try-catch で制御 try-catch で制御
スコープ CoroutineScope CoroutineScope suspend 関数内

5. 実践比較:API呼び出し3パターン

(A) launch:結果不要な非同期

launch {
    apiCall() // 戻り値を使わない
    println("送信完了")
}

(B) async / await:結果を並列取得

val user = async { fetchUser() }
val posts = async { fetchPosts() }

val result = "${user.await()} + ${posts.await()}"
println(result)

(C) withContext:順次スレッド切り替え

val user = withContext(Dispatchers.IO) { fetchUser() }
val posts = withContext(Dispatchers.IO) { fetchPosts() }

println("結果: $user + $posts")

6. 図解:それぞれの動作の違い


7. 使い分けの指針

シーン 最適な選択 理由
戻り値が不要な非同期処理 launch 軽量で Job 管理が容易
複数APIを並列で取得 async / await 並行処理ができる
スレッドを切り替えて実行 withContext シンプルで安全
UI → IO → UI 切替 withContext Main ↔ IO の切替が簡単
バッチ処理・データ集約 async + awaitAll() 効率的に結果をまとめる

8. 例:3つの構文を組み合わせた実践コード

suspend fun fetchUser() = withContext(Dispatchers.IO) {
    delay(1000)
    " User"
}

suspend fun fetchPosts() = withContext(Dispatchers.IO) {
    delay(800)
    " Posts"
}

fun main() = runBlocking {
    launch {
        println("データ取得開始")

        val userDeferred = async { fetchUser() }
        val postsDeferred = async { fetchPosts() }

        val result = "${userDeferred.await()} + ${postsDeferred.await()}"
        println("結果: $result")

        println("完了しました")
    }
}

まとめ

概念 launch async / await withContext
戻り値 Job Deferred T
並行性 あり あり なし(順次)
スレッド切替
典型用途 結果不要処理 並列計算・API集約 IO処理・UI更新
例外処理 try-catch try-catch try-catch
構造化並行性
  • launch:結果不要の非同期処理に最適
  • async / await:並行実行+結果が必要な処理に最適
  • withContext:スレッドを安全に切り替えるための順次処理に最適

3つを正しく使い分けることで、
Kotlin アプリの 非同期処理は安全・高速・美しく なります。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?