У нас есть особый вариант использования, и мне нужна помощь, чтобы выяснить, можем ли мы решить нашу проблему с сопрограммами Котлина или нам нужно полагаться на 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, который делает его более читабельным, например, async / await в JavaScript. Чтобы помнить, в 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.
Спасибо