在主线程中运行非阻塞协同程序

问题描述 投票:0回答:2

我们有一个特殊的用例,如果我们可以用Kotlin的协同程序解决问题,或者我们必须依赖CompletableFutures,我需要帮助才能找到答案。

基本上,我们为单线程本身的服务器编写插件。这意味着,我们可以使用不同的钩子来添加逻辑,这个逻辑总是在主线程内运行,不能被阻塞。此外,在使用服务器的API时,我们必须在主线程内,因为给定的方法不是线程安全的。

为了使用异步代码,我们使用服务器的调度程序来生成在后台运行异步任务的生产者/消费者系统,并将结果同步回服务器的主线程。实现不应该那么重要,所以这里只是一个例子,说明这在实践中是怎样的:

// execute hook that runs when a user on the server runs a command
override fun execute(sender: CommandSender, args: Array<out String>) {
    // call comes from the main thread
    db.fetchBalance(sender.name)
        // fetchBalance runs asynchronous code without blocking
        // the current thread by utilizing a consumer/producer system
        .thenAccept {
            // the CompletableFuture is resolved after completion

            // here we are in the main thread again, so that we can access
            // server methods in a thread safe manner
            sender.sendMessage("Your balance: $it")
        }
}

现在我的问题是,如果上面的例子可以用Kotlin代码替换它使它更具可读性,比如JavaScript中的async / await。要记住,在JavaScript中我们可以这样做:

async function onBalanceRequest(client, name) {
  let balance = await db.fetchBalance(name);
  client.sendMessage("Your money: " + balance);
}

几天前我问了一个关于async / await的类似问题,这导致了一个看起来像这样的解决方案:

private fun onBalanceRequest(sender: CommandSender) {
    // call comes from the main thread
    GlobalScope.launch {
        // here we are within a new thread
        val money = db.fetchBalance(sender.name).join()
        // here we are within the same thread, which is
        // not the main thread, so the code below isn't safe
        sender.sendMessage("Your balance: $money")
    }
}

正如评论中所描述的那样,问题是,在“等待未来”之后,代码在协同程序的线程中运行。所以我的问题是,如果我们能够实现像我用协同程序描述的东西,或者它们根本不是针对这个用例而制作的。我已经读过有关为衍生协程指定线程的可能性,但是此线程将被阻止,因此无法工作。

如果CompletableFutures是解决这个问题的唯一方法,我们会坚持使用它们,但我想尝试使用协同程序,因为它们比CompletableFutures更好地编写和处理。

谢谢

kotlin kotlinx.coroutines
2个回答
1
投票

尝试withContext功能。将代码包装在其中,它将在所需的上下文中执行。

例如:

withContext(Dispatchers.Main) {
    //This will run in Main Thread
}

您可以使用您选择的Coroutines Context替换Dispatchers.Main

注意:withContext函数是“暂停”函数,它必须只在Coroutine Scope中执行


0
投票

立即执行

如果您确实需要立即执行该怎么办?为此,您可以使用

Dispatchers.Main.immediate

当协程已经在正确的上下文中时立即执行协同程序

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)

    launch(Dispatchers.Main.immediate) {
        log("A")
    }

    log("B")
}

打印

OUTPUT:
// A
// B
© www.soinside.com 2019 - 2024. All rights reserved.