繁体   English   中英

如何让协程 function 像 AsyncTasks 一样等待上一个调用?

[英]How to make coroutine function wait for the previous call like with AsyncTasks?

所以我重写了一堆 AsyncTask 代码来使用协程,但是有一个竞争条件问题。 问题是在之前的 doInBackground(现在是一个挂起函数)中,有一个数据库查询来获取任何未上传的数据,然后有一个网络请求发布该数据,最后我们更新数据库以不再获取该数据。 问题是这个 function 可以在任何给定时刻从应用程序中的几个不同位置调用。 以前这没什么大不了的,因为 AsyncTask 会等待前一个 doInBackground 完成,因为默认情况下所有 AsyncTask 在 using.execute() 时共享同一个工作线程。 然而,对于协程,它们将并行运行,导致竞争条件和重复上传。 在 Kotlin 和协程中处理这个问题的最佳方法是什么?

她是一个简化的例子,uploadData function 是从代码库的不同位置调用的,并且可以在它已经从其他地方运行时调用。 SomeUploader class 在应用程序中任何需要的地方都注入了匕首。

class SomeUploader @Inject constructor(private val someRetrofitService: SomeRetrofitService) {

suspend fun uploadData(ctx: Context) = withContext(Dispatchers.IO) {
    doUpload(ctx, getNotUploadedDataFromDatabase(ctx))
}

private suspend fun doUpload(ctx: Context, cursor: Cursor?) = withContext(Dispatchers.IO) {
    if (cursor != null && cursor.count > 0) {
        RetrofitNetworkManager.performRequest(TAG) {
            var responseData: List<UpdateDataDto>? = null
            val response = someRetrofitService.updateData(convertToRequestBody(cursor))
            response.body()?.let {
                if (RetrofitNetworkManager.validateResponse(TAG, response)) {
                    responseData = it.Data
                }
            }
            return@performRequest responseData
        }?.let {
            setDataToUploadedInDatabase(it, ctx)
        } ?: run {
            // Request failed
        }
    }
}

...

总结一下:您有一个无法同时调用的阻塞调用。 1

因为调用阻塞了线程,所以您正确使用Dispatchers.IO 但是Dispatchers.IO中有很多线程,您的doUpload调用将是并发的。

您可以使用互斥锁进行互斥。

private val uploadDataLock = Mutex()

suspend fun uploadData(ctx: Context) = uploadDataLock.withLock {
  withContext(Dispatchers.IO) {

[1] 我怀疑这个要求是解决并发问题的最佳方法。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM