これら2つのコードブロックの違いを教えてください。初回は421を印刷しますが、2回目は606を印刷します。
fun main(args: Array<String>) = runBlocking {
var time = measureTimeMillis {
val one = async { one() }
val two = async { two() }
val int1 = one.await()
val int2 = two.await()
println(int1 + int2)
}
println(time)
time = measureTimeMillis {
val one = async { one() }.await()
val two = async { two() }.await()
println(one + two)
}
print(time)
}
suspend fun one(): Int {
delay(200)
return 12
}
suspend fun two(): Int {
delay(400)
return 23
}
val one = async { one() }
val two = async { two() }
val int1 = one.await()
val int2 = two.await()
これが何をするか:
val one = async { one() }.await()
val two = async { two() }.await()
これが何をするか:
ここには並行性はありません。純粋にシーケンシャルなコードです。実際、シーケンシャル実行の場合、async
を使用するべきではありません。適切なイディオムは
val one = withContext(Dispatchers.Default) { one() }
val two = withContext(Dispatchers.Default) { two() }
最初のバリアントでは、両方の非同期呼び出しに対してDeferred<Int>
を取得します。 Deferred
のドキュメント が示すように、遅延オブジェクトが存在する可能性のある状態がいくつかあります。外部からは、その状態はnew
またはactive
のいずれかですが、まだ完了していません。ただし、2番目のバリアントでは、最初のasync-awaitには既にcompleted
状態が必要です。そうでない場合は、そこに値を設定できません。ただし、async{one()}.await()
では、2番目のasync
はまだ不明です。また、await()
の戻り値はInt
ではなくDeferred
になっているため、それまでにコルーチンが実行されている必要があります。 await()
のドキュメント も確認してください。
言い換えると:
val one = async { one() }
val two = async { two() }
one
とtwo
の両方がDeferred<Int>
になりました。まだ呼び出されていません(またはまだ呼び出されている可能性があります)。 one.await()
を呼び出すと、すぐにone
とtwo
の両方が開始される場合があります(コード内でtwo.await()
を使用していなくても)。
ただし、2番目のバリアントでは:
val one = async { one() }.await()
val two = async { two() }.await()
async {one()}
のコルーチンを作成しても、await()
を呼び出しているため、すぐにone
に値を設定する必要があります。 one
とtwo
のタイプは両方ともInt
です。したがって、これらの行の最初の行がヒットするとすぐに、非同期コードをすぐに実行する必要があります。それまでに、最初の値を待つ間に別の非同期呼び出しを実行する必要があることを誰も知りません。最初のものがawait
を持たない場合、コルーチンは再び並列に実行されます、例えば:
val one = async { one() }
val two = async { two() }.await()
one()
とtwo()
を並行して実行します。
したがって、これを要約すると、それらのコルーチンのみが待機中に並行して実行でき、それまでに既知/生成されます。
Marko Topolnikの回答の後、さまざまなバリエーションを試しましたが、受け入れられた回答だと思います。しかし、興味深いのは、コルーチンを開始してawaitを呼び出さない場合、関数は開始するが終了しないことです。以下は私のコードです。
fun main(args: Array<String>) = runBlocking {
var time = measureTimeMillis {
val one = async { one(1) }
val two = async { two(1) }
val int1 = one.await()
val int2 = two.await()
}
println("time: $time")
time = measureTimeMillis {
val one = async { one(2) }.await()
val two = async { two(2) }.await()
}
println("time: $time")
time = measureTimeMillis {
val one = async { one(3) }
val two = async { two(3) }
}
println("time: $time")
}
suspend fun one(iteration: Int): Int {
println("func1 start, iteration $iteration")
delay(200)
println("func1 end, iteration $iteration")
return 12
}
suspend fun two(iteration: Int): Int {
println("func2 start, iteration $iteration")
delay(400)
println("func2 end, iteration $iteration")
return 23
}
そして出力は、
func1の開始、反復1
func2開始、反復1
func1終了、反復1
func2終了、反復1
時間:430
func1の開始、反復2
func1終了、反復2
func2の開始、反復2
func2終了、反復2
時間:607
func1開始、反復3
時間:2
func2開始、反復3
プロセスは終了コード0で終了しました