Multithreading 请求-响应内并发的协同路由

Multithreading 请求-响应内并发的协同路由,multithreading,web-services,kotlin,kotlin-coroutines,Multithreading,Web Services,Kotlin,Kotlin Coroutines,假设我正在运行一个简单的web服务器,它分配100个线程来处理传入的请求。当一个请求到来时,一个线程被分配并被阻塞,直到一个响应可用为止。一旦有响应可用,响应就被发送出去,线程再次空闲 要处理一个请求,我需要进行2次数据库调用,并基本上总结结果: 挂起getUserData(用户名:字符串):字符串={ val firstName=async{database1.findUser(username)}//一个挂起的函数 val lastName=async{database2.findUser

假设我正在运行一个简单的web服务器,它分配100个线程来处理传入的请求。当一个请求到来时,一个线程被分配并被阻塞,直到一个响应可用为止。一旦有响应可用,响应就被发送出去,线程再次空闲

要处理一个请求,我需要进行2次数据库调用,并基本上总结结果:


挂起getUserData(用户名:字符串):字符串={
val firstName=async{database1.findUser(username)}//一个挂起的函数
val lastName=async{database2.findUser(username)}//一个挂起的函数
返回firstName.await()+lastName.await();
}
假设我有一个main方法调用上述方法来服务请求:


趣味主站(用户名){
运行阻塞{
返回用户数据(用户名)
}
}
我的理解是getUserData中的异步代码将在

这表明:

  • 除了处理请求的100个线程之外,我还有一个(较小的)线程池,由~4-8个线程组成,用于处理数据库调用
  • 假设我有4个CPU,并且假设每个db调用需要约750ms:如果我开始每秒接收50个请求,处理co例程的4个线程将被4个请求阻塞,剩下的44个线程将挂起,等待响应
这引出了我的问题:

  • 我的理解正确吗?这就是实际发生的情况,或者默认Dispatcher中的4个线程管理一个事件循环,因此实际上可以并发处理大量IO,一次执行所有50个请求(假设db.findUser返回一个未来或其他东西)
  • 是否有任何方法(对于请求-响应,使用固定的100个线程,以及这些线程的阻塞性质)在同一线程上并发执行伪代码。因为这是IO绑定的,所以我正在寻找类似于NodeJS的事件循环模型的东西,除了在同一个线程上运行之外。我只想并发执行数据库调用,而不是按顺序执行

  • 注意:我不是在寻找不同的服务器/框架。相反,考虑到我已经拥有的,我很好奇是否可以利用协同路由来提高并发性。如果没有,我可以按顺序运行查询。

    你说的
    db.findUser
    是一个挂起的函数,这意味着它不会阻止调用线程<代码>默认调度程序中的4个线程是否管理事件循环--是<代码>一次执行所有50个请求--是
    假设db.findUser返回未来或某个东西
    ——您说它是一个可挂起的函数,所以它不会返回未来,而是返回实际结果。
    我的理解是getUserData中的异步代码将在默认调度程序上运行
    ——您不能单独调用
    异步
    ,您需要一个
    CoroutineScope
    来调用它,它将确定调度器。如果使用像
    GlobalScope
    这样的空范围,则默认值为
    default
    dispatcher。但是实际上,您应该将
    getUserData
    的主体包含在
    coroutineScope{…}
    块中,否则在两个块中的一个失败的情况下,代码将泄漏coroutines。@MarkoTopolnik不是由调用它的
    runBlocking
    处理的。如果第一个
    async{…}
    失败,那么它将抛出
    firstName.await()
    ,第二个基本上继续运行。runBlocking不会得到错误并终止第二个错误吗?它转义方法,但不转义调用(
    runBlocking
    )范围。是的,但这意味着它不包含在函数中,您必须使用外部
    runBlocking
    来修复它。内部
    coroutineScope
    是正确的习惯用法和最佳实践。可以从
    runBlocking
    调用该函数,也可以不调用该函数。另外,如果没有
    coroutineScope
    代码甚至都不会编译,就没有
    coroutineScope
    可以调用
    async
    。您说过
    db.findUser
    是一个挂起的函数,这意味着它不会阻止调用线程<代码>默认调度程序中的4个线程是否管理事件循环--是<代码>一次执行所有50个请求--是
    假设db.findUser返回未来或某个东西
    ——您说它是一个可挂起的函数,所以它不会返回未来,而是返回实际结果。
    我的理解是getUserData中的异步代码将在默认调度程序上运行
    ——您不能单独调用
    异步
    ,您需要一个
    CoroutineScope
    来调用它,它将确定调度器。如果使用像
    GlobalScope
    这样的空范围,则默认值为
    default
    dispatcher。但是实际上,您应该将
    getUserData
    的主体包含在
    coroutineScope{…}
    块中,否则在两个块中的一个失败的情况下,代码将泄漏coroutines。@MarkoTopolnik不是由调用它的
    runBlocking
    处理的。如果第一个
    async{…}
    失败,那么它将抛出
    firstName.await()
    ,第二个基本上继续运行。runBlocking不会得到错误并终止第二个错误吗?它转义方法,但不转义调用(
    runBlocking
    )范围。是的,但这意味着它不包含在函数中,您必须使用外部
    runBlocking
    来修复它。内部
    coroutineScope
    是正确的习惯用法和最佳实践。可以从
    runBlocking
    调用该函数,也可以不调用该函数。此外,如果没有
    coroutineScope
    代码甚至无法编译,那么就没有
    coroutineScope
    可以调用
    async