【问题标题】:How is blocking in a suspend function different than calling an async function?挂起函数中的阻塞与调用异步函数有何不同?
【发布时间】:2021-09-29 16:38:06
【问题描述】:

我正在使用 OkHttp 发出同步 http 请求。为了避免阻塞主线程,我将阻塞的网络调用包裹在一个挂起函数和withContext(Dispatchers.IO)

    suspend fun run(): String {
        val client = OkHttpClient()
        val request = Request.Builder()
            .url("https://publicobject.com/helloworld.txt")
            .build()
        return withContext(Dispatchers.IO) {
            val response = client.newCall(request).execute()
            return@withContext "Request completed successfully"
        }
    }

Android Studio 给我一个警告,execute() 是一个“不适当的阻塞方法调用”。我的理解是,execute() 会在 http 请求期间阻塞,在请求期间占用 Dispatchers.IO 中的一个线程,这并不理想。为了避免这个问题,我可以使用包裹在suspendCoroutine中的异步版本的请求

    suspend fun runAsync(): String = suspendCoroutine { continuation ->
        val client = OkHttpClient()
        val request = Request.Builder()
            .url("http://publicobject.com/helloworld.txt")
            .build()

        client.newCall(request).enqueue(object : Callback {
            override fun onFailure(call: Call, e: IOException) {
                continuation.resumeWithException(e)
            }

            override fun onResponse(call: Call, response: Response) {
                response.use {
                    if (!response.isSuccessful) throw IOException("Unexpected code $response")
                    continuation.resume("Request completed successfully")
                }
            }
        })
    }

这避免了警告,但我不明白它在功能上与上面的同步版本有何不同。我假设 http 调用的异步版本使用线程来等待请求。这个假设正确吗?如果没有,异步函数如何等待回调返回?

【问题讨论】:

    标签: kotlin kotlin-coroutines


    【解决方案1】:

    我不明白它在功能上与上面的同步版本有何不同。我假设 http 调用的异步版本使用线程来等待请求。这个假设正确吗?如果没有,异步函数如何等待回调返回?

    这是不正确的,异步方法的要点是在调用发生时没有线程被阻塞。您的第二种方法实现了这一点——当协程挂起时,它根本不在任何线程上。根据OkHttp 的实现细节,可能会或可能不会因为依赖阻塞IO 而阻塞某些内部线程。理想情况下,它应该根据 Java NIO(更典型的是通过 Netty 库)实现,并依赖于称为 Selector 的低级非阻塞原语。

    正确的方法是实现暂停的方式,除了用户 Tenfour04 指出的那样,OkHttpClient 已经在其await() 函数中提供了该实现。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-06-27
      • 1970-01-01
      • 1970-01-01
      • 2012-07-25
      • 2020-07-19
      • 1970-01-01
      • 2020-03-26
      • 2020-10-25
      相关资源
      最近更新 更多