1
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】Kotlin の `async / await` 徹底解説

Posted at

はじめに

―― 並行処理でアプリを高速化するコルーチンの真髄 ――

Kotlin のコルーチン(Coroutine)は、非同期処理をシンプルかつ安全に書ける仕組みです。
その中でも特に重要な構文が async / await
これを使うと、複数の処理を並行して実行し、結果を同時に待つことができます。


1. asyncawait の基本

概念

  • async:非同期タスクを起動し、Deferred<T> を返す。
  • await:その結果(Deferred)を待ち、完了した値を受け取る。

両者を組み合わせることで、複数の処理を同時に進めつつ結果を集約できます。


サンプルコード

import kotlinx.coroutines.*

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

    val orange = async {
        delay(500)
        "🍊 Orange"
    }

    println("結果を待っています...")
    val result = "${apple.await()} & ${orange.await()}"
    println("完了! -> $result")
}

出力:

結果を待っています...
完了! -> 🍎 Apple & 🍊 Orange

各タスクは同時に動作するため、全体で約1秒で終了します。
(1,000ms + 500ms ではなく、max(1000, 500)


2. asynclaunch の違い

比較項目 async launch
戻り値 Deferred<T>(値を返す) Job(値を返さない)
用途 結果を受け取りたい 処理だけ実行したい
結果の取得 .await() .join()
使用例 並列計算・API呼び出し UI更新・ログ出力など

例:

val result = async { calcResult() }.await()
launch { saveLog() }.join()

3. asyncCoroutineScope 内でのみ使用可能

// ✅ OK:コルーチンスコープ内
runBlocking {
    async { println("OK") }
}

// ❌ NG:スコープ外ではエラー
async { println("NG") }

asyncrunBlocking, coroutineScope, launch などの中でしか使えません。


4. Dispatcher を指定してスレッドを切り替える

async は、どのスレッドで処理を行うか指定できます。

Dispatcher 説明 代表的な用途
Dispatchers.Default CPU負荷の高い計算用 数値計算、並列処理
Dispatchers.IO I/O最適化 ネットワーク、DB、ファイル
Dispatchers.Main メインスレッド UI更新(Android)
val data = async(Dispatchers.IO) {
    fetchFromNetwork()
}.await()

5. 複数APIを並行して呼び出す実例

suspend fun fetchUser(): String {
    delay(1000)
    return "UserData"
}

suspend fun fetchPosts(): String {
    delay(800)
    return "PostData"
}

fun main() = runBlocking {
    val userDeferred = async { fetchUser() }
    val postsDeferred = async { fetchPosts() }

    println("両方の結果を待機中...")
    val result = "${userDeferred.await()} + ${postsDeferred.await()}"
    println("完了! -> $result")
}

実行時間:
2つの処理を並列化することで、合計 1.8秒 → 約1秒 に短縮。


6. start = CoroutineStart.LAZY で遅延起動

通常、async は呼び出し時点で即実行されます。
必要になってから動かしたい場合は、LAZY 起動を使います。

val deferred = async(start = CoroutineStart.LAZY) {
    heavyTask()
}

println("まだ開始していません…")
deferred.start() // 手動で開始
val result = deferred.await()

7. エラー処理(try-catch)

await() は例外をスローします。
そのため try-catch で安全に包むのがベストです。

try {
    val data = async { apiCall() }.await()
    println("取得成功: $data")
} catch (e: Exception) {
    println("エラー発生: ${e.message}")
}

8. 構造化並行性(Structured Concurrency)

Kotlin の async/await構造化並行性 に従います。
つまり、親スコープが終了すると、子コルーチンも自動的にキャンセルされます。

coroutineScope {
    val a = async { taskA() }
    val b = async { taskB() }
    // スコープ終了時に a,b も終了
}

これにより、リークしない安全な並行処理が実現します。


9. asyncwithContext の違い

比較項目 async withContext
並行実行 可能 不可(順次実行)
戻り値 Deferred<T>(後で受け取る) 直接 T を返す
使い分け 並列計算・複数API呼び出し 単一処理でスレッド切替したい時

例:

val user = withContext(Dispatchers.IO) { fetchUser() } // 順次実行
val posts = withContext(Dispatchers.IO) { fetchPosts() } // 順次実行

並列化したい場合は async を選びましょう。


まとめ

概要 内容
async 非同期タスクを起動し、Deferred<T>を返す
await タスクの完了を待ち、結果を取得する
メリット 複数の処理を並行して実行できる
典型利用例 複数API呼び出し、並列計算、バッチ処理
注意点 スコープ内で使用、例外処理を忘れずに
  • async / await は Kotlin コルーチンの非同期並行処理の中核
  • I/O と計算を分離し、効率的にタスクをまとめて処理できる
  • 構造化並行性により、メモリリークのない安全な非同期処理が可能

1
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
1
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?