Asynchronous 如何对Kotlin中的多个项目异步执行网络请求?

Asynchronous 如何对Kotlin中的多个项目异步执行网络请求?,asynchronous,kotlin,coroutine,Asynchronous,Kotlin,Coroutine,我有一个需要从web服务检索的项目列表。看起来最好的方法是通过一个频道,但我不能让它们同时运行。为了简单起见,我已将问题简化为一个小应用程序,其中包含一个模拟网络调用的循环 import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.launch import kotlinx.coroutines.runBlocking import java.text.SimpleDateFormat import java.ut

我有一个需要从web服务检索的项目列表。看起来最好的方法是通过一个频道,但我不能让它们同时运行。为了简单起见,我已将问题简化为一个小应用程序,其中包含一个模拟网络调用的循环


import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import java.text.SimpleDateFormat
import java.util.*
import kotlin.random.Random

private val charPool: List<Char> = ('a'..'z') + ('A'..'Z') + ('0'..'9')
private val sdf =SimpleDateFormat("YYYY-MM-dd kk:mm:ss.SSSS")
const val NUMBER_OF_LOOPS = 5

fun main() = runBlocking<Unit> {
    val channel = Channel<String>()
    log("First thing")
    repeat(NUMBER_OF_LOOPS) {
        launch {
            channel.send(getValue(it))
        }
    }
    log("Second Thing")
    launch {
        repeat(NUMBER_OF_LOOPS) {
            val value = channel.receive()
            log(value)
        }
    }
    log("All Done.")
}

fun getValue(i: Int): String {
    log(String.format("Starting value for %d", i))
    var rand: String = ""
    repeat(100000) {
        rand = (1..256)
            .map { Random.nextInt(0, charPool.size) }
            .map(charPool::get)
            .joinToString("")
    }
    log(String.format("Done processing for %d", i))
    return rand
}

fun log(value: String){
    println(String.format("%s %s", sdf.format(Date()), value))
}
我希望所有的“起始值…”日志显示在任何“完成处理”日志之前,但正如您所看到的,它们都是同步运行的


有更好的方法吗?

代码的主要问题是启动子协同路由的协同路由范围由
runBlocking
提供,默认情况下,它是您的
主线程。此上下文由
launch
创建的子协同程序继承。如果将
Thread.currentThread().name
的输出添加到
log
函数中,则可以很容易地看到这一点

将调度程序指定为运行阻塞的参数,例如:

runBlocking(Dispatchers.Default) { ... }
话虽如此,我觉得你把频道的事情搞得很复杂。您可以使用
async
使这些请求并发

例如,如果将
main
方法更改为以下内容:

// Note the explicit specification of the dispatcher here...
fun main() = runBlocking<Unit>(Dispatchers.Default) {
  log("First thing")

  val results = (1..NUMBER_OF_LOOPS).map {
    async { getValue(it) }
  }.awaitAll()

  log("Results: $results")

  log("All Done.")
}
如果您不调用
awaitAll()
,您将得到一个
延迟
列表,您可以编写该列表,例如

val first = (1..x).map {
  async { something(it) }
}

val second = (1..y).map {
  async { somethingElse(it) }
}

(first + second).awaitAll()
我建议阅读,特别是关于结构化并发的部分。使用异步函数正确处理故障可能很棘手,在将此类代码投入生产之前需要额外注意

DefaultDispatcher-worker-4 2019-11-20 14:51:23.0884 Starting value for 3
DefaultDispatcher-worker-1 2019-11-20 14:51:23.0884 Starting value for 1
DefaultDispatcher-worker-5 2019-11-20 14:51:23.0884 Starting value for 4
DefaultDispatcher-worker-6 2019-11-20 14:51:23.0884 Starting value for 5
DefaultDispatcher-worker-3 2019-11-20 14:51:23.0884 Starting value for 2
DefaultDispatcher-worker-4 2019-11-20 14:51:25.0547 Done processing for 3
DefaultDispatcher-worker-6 2019-11-20 14:51:25.0599 Done processing for 5
DefaultDispatcher-worker-1 2019-11-20 14:51:25.0601 Done processing for 1
DefaultDispatcher-worker-5 2019-11-20 14:51:25.0775 Done processing for 4
DefaultDispatcher-worker-3 2019-11-20 14:51:25.0779 Done processing for 2
DefaultDispatcher-worker-3 2019-11-20 14:51:25.0780 Results: [U5VZ..., J4u0..., HWqg..., 1VrO..., ecS1...]
DefaultDispatcher-worker-3 2019-11-20 14:51:25.0780 All Done.

val first = (1..x).map {
  async { something(it) }
}

val second = (1..y).map {
  async { somethingElse(it) }
}

(first + second).awaitAll()