asyncとは何か、Deferredと並列コルーチンの仕組み

著者: IT Sectr 公開日: 2026-06-22 読了時間: 8 分

async — KotlinのCoroutine Builderで、コルーチンを起動し、非同期操作の結果を取得するためのDeferred<T>オブジェクトを返します。asyncは複数のタスクを並列に実行し、await()を通じて結果をまとめることができます。JetBrainsのガイド(2024)によると、asyncはコルーチンにおける並列計算を組織するのに最適な方法です。

まとめ

  • async — 非同期操作の結果をもつDeferred<T>を返すコルーチンビルダー
  • Deferred — Jobを継承し、結果を得るためのawait()メソッドを持つ非同期プロミス
  • asyncは独立したタスクを並列に実行でき、総時間を削減する
  • await() — ブロックせずに結果を得られるまでコルーチンを一時停止するsuspend関数
  • 構造化された並行性により、エラー時にすべての並列タスクがキャンセルされることが保証される

Kotlin Coroutinesでのasyncとは?

async — CoroutineScopeの拡張関数で、結果を返すコルーチンを作成します。launchとは異なり、asyncはDeferred<T> — 将来の値を表すオブジェクトを返します。asyncで起動されたコルーチンは他のコルーチンと並行で実行され、計算を並列化できます。

asyncは、非同期操作の結果が後続処理に必要な場合に使用されます:複数のソースからのデータ読み込み、コレクションのバッチ処理、複数のAPIへの並列リクエストなどです。Deferredは即座に作成され、コルーチンが完了すると結果が利用可能になります。

kotlin
import kotlinx.coroutines.*

suspend fun String.delayedValue(): String {
    delay(1000L)
    return this
}

fun main() = runBlocking {
    val deferred: Deferred<String> = async { "Hello".delayedValue() }
    println(deferred.await())
}

asyncとDeferredの構文

asyncのシグネチャはlaunchと同じです:同じCoroutineContext、CoroutineStartパラメータ、そしてsuspendブロックです。違いは戻り値のタイプです — Jobの代わりにDeferred<T>を返します。ただしTはブロックの最終式が返す結果のタイプです。

kotlin
public fun <T> CoroutineScope.async(
    context: CoroutineContext = EmptyCoroutineContext,
    start: CoroutineStart = CoroutineStart.DEFAULT,
    block: suspend CoroutineScope.() -> T
): Deferred<T>

Deferred<T> — Jobを継承し、await()、getCompleted()、getCompletionExceptionOrNull()メソッドを追加するインタフェースです。await()はsuspend関数で、コルーチンまたは他のsuspend関数の内部でのみ呼び出せます。getCompleted()は非ブロックングメソッドで、コルーチンがまだ完了していない場合は例外をスローします。

asyncによる並列タスク

asyncの主な利点は、タスクを並列に実行できることです。それぞれの操作を順番に待つのではなく、asyncはコルーチンを同時に起動し、総時間を最も長い操作の所要時間に縮短します。

並列データ読み込み

タイピカルなシナリオ — 三つの並列asyncリクエストでユーザープロフィール、設定、注文履歴を読み込むことです。すべてが完了すると、結果が1つのデータモデルにまとめられます。

kotlin
suspend fun loadUserDashboard(userId: String): Dashboard = coroutineScope {
    val profile = async { api.getProfile(userId) }
    val settings = async { api.getSettings(userId) }
    val orders = async { api.getRecentOrders(userId) }

    Dashboard(
        profile = profile.await(),
        settings = settings.await(),
        orders = orders.await()
    )
}

coroutineScope関数はチャイルドコルーチンを起動し、結果を返す前に完了を待ちます。ブロック全体が順番ではなく並列に実行されます。

Deferred結果の処理

Deferredは結果を取り扱うための複数のメソッドをサポートしています。await()に加え、状態の確認、完了値の取得、Kotlin Coroutinesのユーティリティ関数を介して複数のDeferredをまとめることができます。

メソッド説明Suspend?
await()結果を得られるまでコルーチンを一時停止するはい
getCompleted()コルーチンが完了していれば結果を返すいいえ
getCompletionExceptionOrNull()エラー時に例外またはnullを返すいいえ
isCompletedコルーチンが完了したか確認するいいえ

Deferredのリストをまとめるには、awaitAll()を使用します — この関数はコレクション内のすべてのDeferredが完了するまで実行を一時停止します。ひとつでもエラーで完了した場合、awaitAll()は例外をスローします。

kotlin
suspend fun <T> loadAll(requests: List<suspend () -> T>): List<T> {
    return coroutineScope {
        val deferreds = requests.map { async { it() } }
        deferreds.awaitAll()
    }
}

asyncとlaunchの違い

asyncとlaunchの選択は、コルーチンの結果が必要かどうかによります。launchはJobを返し、fire-and-forget操作に適しており、asyncはDeferredを返し、データを返すタスクに使用されます。構文とパラメータは同じです。

  • launch → Job(結果なし)、async → Deferred<T>(結果T)
  • launch — fire-and-forgetタスク(ログ、キャッシュ、アナリティクス送信)
  • async — 並列計算(複数APIからの読み込み、バッチ処理)
  • 両方とも構造化された並行性とCoroutineStartパラメータをサポート
  • await()はDeferredでのみ利用可能、launchは結果を提供しない

重要なルール:fire-and-forgetにasyncを使用しないでください。コルーチンの結果が不要な場合はlaunchを使用します。asyncはDeferredの作成によりオーバーヘッドが生じ、そのようなシナリオでは試当ではありません。

モバイル開発でのasyncの例

Androidでは、asyncはViewModelやUseCases内の並列操作に使用されます。タイピカルなシナリオ:プロフィールとニュースフィードの同時読み込み、複数の天気予報サービスからの天気取得、サーバーとのバッチデータ同期などがあります。

kotlin
class HomeViewModel : ViewModel() {
    fun loadHomeScreen() {
        viewModelScope.launch {
            val userData = async(Dispatchers.IO) { repository.getUserData() }
            val newsFeed = async(Dispatchers.IO) { repository.getNewsFeed() }
            val notifications = async(Dispatchers.IO) { repository.getNotifications() }

            val state = HomeState(
                user = userData.await(),
                news = newsFeed.await(),
                unread = notifications.await()
            )
            _uiState.update { state }
        }
    }
}

エラーをアイソレートするために、asyncのグループをcoroutineScopeまたはsupervisorScopeで囲むことが推奨されます。supervisorScopeは一つが失敗しても他のasyncコルーチンが続行できます — 非クリティカルな操作に便利です。

よくある質問

asyncをawaitなしで使用できますか?

できますが意味がありません。await()なしのasyncはコルーチンを起動しますが、結果が失われます。結果が不要な場合はlaunchを使用してください — Deferredを作成せず、メモリとパフォーマンスが向上します。

asyncは例外をどのように処理しますか?

async内の例外はDeferredに保管されます。await()を呼ぶとこの例外がスローされます。スローせずに確認するには、getCompletionExceptionOrNull()を使用します。coroutineScopeを使用すると、エラーがすべてのチャイルドコルーチンをキャンセルします。

Kotlin CoroutinesでのawaitAllとは?

awaitAll() — Iterable<Deferred<T>>の拡張関数で、すべてのDeferredが完了するまでコルーチンを一時停止します。結果のリストを返します。ひとつでもDeferredが失敗すると、例外をスローして残りをキャンセルします。

asyncはGlobalScope.asyncとどう違いますか?

はい。asyncはCoroutineScopeの拡張関数で、スコープに結びつくされています。GlobalScope.asyncはライフサイクルに結びつかずにコルーチンを作成します — 無限に実行される可能性があります。AndroidではメモリリークのリスクからGlobalScopeは推奨されません。

並列リクエストに何つのasyncコルーチンを起動できますか?

数はディスパッチャによります:Dispatchers.IOは最大64スレッドをサポートし、Dispatchers.DefaultはCPUコア数までサポートします。バッチ操作には、SemaphoreまたはawaitAllとの組み合わせでmapNotNullを使用して並列度を制限します。

まとめ

  • async — 非同期結果取得のためにDeferred<T>を返すコルーチンビルダー
  • DeferredはJobを継承し、await()、getCompleted()、getCompletionExceptionOrNull()メソッドを追加
  • 並列実行により、総時間が最も長い操作の所要時間に縮短される
  • awaitAll() — コレクション内のすべてのDeferredを待つためのユーティリティ
  • coroutineScope — キャンセル保証付きのasyncグループに推奨されるラッパー
  • asyncをfire-and-forgetに使用しないでください — 代わりにlaunchを使用
  • Androidでは、asyncはviewModelScopeでViewModel内の並列読み込みに使用

ターンキー方式のモバイルアプリケーションを開発します

IT Sectrは2017年からスタートアップや企業向けにiOS・Androidアプリケーションを開発しています。私たちがご相談に乗り、最適なソリューションをご提案します。

プロジェクトについて相談

こちらもお読みください