kotlin协程在网络请求中如何使用?

我在测试在kotlin的协程里使用网络io是否会导致线程阻塞

suspend fun main() {
    Executors.newSingleThreadExecutor().asCoroutineDispatcher().use {
        dispatcher->  supervisorScope {
            async(dispatcher) {
                while (true){
                    delay(1000)
                    println("打印${Thread.currentThread()}")
                }
            }
            async(dispatcher) {
                val socket = Socket("127.0.0.1", 12365)
                var read = socket.getInputStream()
                while (true){
                    println("读取成功${read.read()},${Thread.currentThread()}")
                    yield()
                }
            }
        }
    }
}

测速结果是InputStream.read确实导致线程阻塞了,而不是挂起。

那么运行在统一个线程下的其他协程也不能运行了,我知道可以使用

          async(Dispatchers.IO) {
                
            }
        withContext(Dispatchers.IO){
            
        }

这些方式把网络请求放入其他线程
但是我想知道的是如果这两个协程都必须运行在同一个线程里时,是否可以通过修改代码(比如异步io等方式)确保第一个协程能每秒打印一次,第二个协程能在接收到数据时及时打印。

阅读 2k
1 个回答

你用 Java NIO 就好了:

import kotlinx.coroutines.*
import java.net.InetSocketAddress
import java.nio.ByteBuffer
import java.nio.channels.AsynchronousSocketChannel
import java.nio.channels.CompletionHandler
import java.util.concurrent.Executors

suspend fun main() {
    Executors.newSingleThreadExecutor().asCoroutineDispatcher().use { dispatcher ->
        supervisorScope {
            async(dispatcher) {
                while (true) {
                    delay(1000)
                    println("打印${Thread.currentThread()}")
                }
            }
            async(dispatcher) {
                val socketChannel = AsynchronousSocketChannel.open()
                val address = InetSocketAddress("127.0.0.1", 12365)
                socketChannel.connect(address).get()

                while (true) {
                    val buffer = ByteBuffer.allocate(1024)
                    socketChannel.read(buffer, null, object : CompletionHandler<Int, Void?> {
                        override fun completed(result: Int, attachment: Void?) {
                            buffer.flip()
                            println("读取成功${buffer.get()},${Thread.currentThread()}")
                        }

                        override fun failed(exc: Throwable, attachment: Void?) {
                            println("读取失败: $exc")
                        }
                    })
                    yield()
                }
            }
        }
    }
}
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进