Kotlin 异步函数不是 运行 并行
Kotlin async function not run in parallel
我有一个 kotlin 函数,如下所示,我希望它可以将同步 IO 操作包装到异步中。
suspend fun <T> runIOAsync(f:suspend () -> T): Deferred<T> = coroutineScope{
async(Dispatchers.IO) {
f()
}
}
然后我在调用方有我的代码
runBlocking {
repeat(5) {
runIOAsync {
println(it)
println(Thread.currentThread())
Thread.sleep(3000)
println("After sleep $it")
}.await()
}
}
但实际输出是
0
Thread[DefaultDispatcher-worker-1 @coroutine#2,5,main]
After sleep 0
1
Thread[DefaultDispatcher-worker-1 @coroutine#3,5,main]
After sleep 1
2
Thread[DefaultDispatcher-worker-1 @coroutine#4,5,main]
After sleep 2
3
Thread[DefaultDispatcher-worker-1 @coroutine#5,5,main]
After sleep 3
4
Thread[DefaultDispatcher-worker-1 @coroutine#6,5,main]
After sleep 4
我的函数中的所有任务似乎都是串行执行的。哪位大神帮忙解释一下
我们暂时搁置runIOAsync
。
您在调用 async()
后立即使用 await()
,这意味着您实际上是在等待异步执行结束,然后再执行下一个。
相反,先启动所有任务,然后等待所有任务。例如,您可以使用 awaitAll:
runBlocking {
List(5) {
async(Dispatchers.IO) {
println(it)
println(Thread.currentThread())
Thread.sleep(3000)
println("After sleep $it")
}
}.awaitAll()
}
此外,您在 runIOAsync
中封装作用域的方式是错误的,即使不调用 await()
,您也会等待异步执行结束(coroutineScope
一个挂起函数,在恢复之前等待其所有子协程。
相反,使用 coroutineScope
来定义协程执行的边界,您甚至不必 await
它们。由于您不需要从此代码中获取值,因此您也可以在此处使用 launch
而不是 async
:
coroutineScope {
repeat(5) {
launch(Dispatchers.IO) {
println(it)
println(Thread.currentThread())
Thread.sleep(3000)
println("After sleep $it")
}
}
}
声明一个 suspend
函数 return 一个 Deferred
应该是一个危险信号,从 API 的角度来看是相当混乱的:如果你暂停它意味着你等等,如果你 return Deferred
这意味着你不等待(你立即 return 一些 运行ning 计算的句柄)。两者兼顾的函数会很奇怪。
如果你想要从 IO 绑定代码中创建挂起代码,你可以使用现有的 withContext 函数:
// this suspends until the code inside is done
withContext(Dispatchers.IO) {
// run some blocking IO code
}
但是请注意,这与定义并发代码无关。如果你想同时 运行 多个东西,即使有挂起函数,你也需要协程构建器,例如上面代码中的 async
或 launch
。
我有一个 kotlin 函数,如下所示,我希望它可以将同步 IO 操作包装到异步中。
suspend fun <T> runIOAsync(f:suspend () -> T): Deferred<T> = coroutineScope{
async(Dispatchers.IO) {
f()
}
}
然后我在调用方有我的代码
runBlocking {
repeat(5) {
runIOAsync {
println(it)
println(Thread.currentThread())
Thread.sleep(3000)
println("After sleep $it")
}.await()
}
}
但实际输出是
0
Thread[DefaultDispatcher-worker-1 @coroutine#2,5,main]
After sleep 0
1
Thread[DefaultDispatcher-worker-1 @coroutine#3,5,main]
After sleep 1
2
Thread[DefaultDispatcher-worker-1 @coroutine#4,5,main]
After sleep 2
3
Thread[DefaultDispatcher-worker-1 @coroutine#5,5,main]
After sleep 3
4
Thread[DefaultDispatcher-worker-1 @coroutine#6,5,main]
After sleep 4
我的函数中的所有任务似乎都是串行执行的。哪位大神帮忙解释一下
我们暂时搁置runIOAsync
。
您在调用 async()
后立即使用 await()
,这意味着您实际上是在等待异步执行结束,然后再执行下一个。
相反,先启动所有任务,然后等待所有任务。例如,您可以使用 awaitAll:
runBlocking {
List(5) {
async(Dispatchers.IO) {
println(it)
println(Thread.currentThread())
Thread.sleep(3000)
println("After sleep $it")
}
}.awaitAll()
}
此外,您在 runIOAsync
中封装作用域的方式是错误的,即使不调用 await()
,您也会等待异步执行结束(coroutineScope
一个挂起函数,在恢复之前等待其所有子协程。
相反,使用 coroutineScope
来定义协程执行的边界,您甚至不必 await
它们。由于您不需要从此代码中获取值,因此您也可以在此处使用 launch
而不是 async
:
coroutineScope {
repeat(5) {
launch(Dispatchers.IO) {
println(it)
println(Thread.currentThread())
Thread.sleep(3000)
println("After sleep $it")
}
}
}
声明一个 suspend
函数 return 一个 Deferred
应该是一个危险信号,从 API 的角度来看是相当混乱的:如果你暂停它意味着你等等,如果你 return Deferred
这意味着你不等待(你立即 return 一些 运行ning 计算的句柄)。两者兼顾的函数会很奇怪。
如果你想要从 IO 绑定代码中创建挂起代码,你可以使用现有的 withContext 函数:
// this suspends until the code inside is done
withContext(Dispatchers.IO) {
// run some blocking IO code
}
但是请注意,这与定义并发代码无关。如果你想同时 运行 多个东西,即使有挂起函数,你也需要协程构建器,例如上面代码中的 async
或 launch
。