如何在 Kotlin 中同时运行阻塞 Java 代码?

Posted

技术标签:

【中文标题】如何在 Kotlin 中同时运行阻塞 Java 代码?【英文标题】:How to run blocking Java code concurrently in Kotlin? 【发布时间】:2021-07-13 21:29:12 【问题描述】:

我正在做一个新的项目,目标是更深入地学习 Kotlin,但我在弄清楚如何将 Kotlin 风格的并发与没有考虑使用协程编写的代码混合使用时遇到了一些麻烦(JOOQ in this案子)。下面的函数在我的一个 DAO 中,在那个映射块中,我想更新数据库中的一堆行。在这个具体的例子中,更新实际上依赖于前一个完成,所以它需要按顺序完成,但我感兴趣的是如何修改这段代码以并行运行更新,因为毫无疑问会使用我有不需要按顺序运行的情况。

suspend fun updateProductChoices(choice: ProductChoice) = withContext(Dispatchers.IO) 
    ctx().transaction  config ->
        val tx = DSL.using(config)

        val previousRank = tx.select(PRODUCT_CHOICE.RANK)
                .from(PRODUCT_CHOICE)
                .where(PRODUCT_CHOICE.STORE_PRODUCT_ID.eq(choice.storeProductId))
                .and(PRODUCT_CHOICE.PRODUCT_ID.eq(choice.productId))
                .fetchOne(PRODUCT_CHOICE.RANK)

        (previousRank + 1..choice.rank).map  rank ->
            tx.update(PRODUCT_CHOICE)
                    .set(PRODUCT_CHOICE.RANK, rank - 1)
                    .where(PRODUCT_CHOICE.PRODUCT_ID.eq(choice.productId))
                    .and(PRODUCT_CHOICE.RANK.eq(rank))
                    .execute()
        
    

最好的方法是将transaction lambda 包装在runBlocking 中,并将每个update 包装在async 中,然后awaitAll 结果?还可能值得注意的是,JOOQ 查询支持executeAsync(),它返回一个CompletionStage

【问题讨论】:

【参考方案1】:

是的,使用 JOOQ 的 executeAsync。使用executeAsync,您可以删除withContext(Dispatchers.IO),因为呼叫不再阻塞。

kotlinx-coroutines-jdk8 库包含与 CompletionStage 的协程集成,因此您可以在其上执行暂停 await (docs)。

要并行执行更新,请注意同一库可以将 CompletionStage 转换为 Deferred (docs)。因此,如果您将调用execute 更改为executeAsync().asDeferred(),您将获得Deferreds 的列表,您可以在其上awaitAll()

【讨论】:

以上是关于如何在 Kotlin 中同时运行阻塞 Java 代码?的主要内容,如果未能解决你的问题,请参考以下文章

如何替换阻塞代码以在 Kotlin 中读取字节

Kotlin 多平台:如何在没有 runBlocking 的情况下以阻塞方式启动协程

Kotlin Coroutine 源码解析 —— 协程是如何运行的

Kotlin Coroutine 源码解析 —— 协程是如何运行的

来自阻塞代码的异步/等待 kotlin 协程

如何使用 Kotlin-Multiplatform 在 iOS 应用程序的后台线程中运行任务?