我需要有关电报机器人 API 包装器架构的建议。所以基本上我需要一种有效处理更新的方法。我已经检查了 kotlin-telgram-bot 是如何做到的。它在单线程上有一个 Courotine 调度程序
Executors.newSingleThreadExecutor().asCoroutineDispatcher()
。按如下方式处理其更新:
private val scope: CoroutineScope = CoroutineScope(coroutineDispatcher)
@Volatile private var job: Job? = null
internal fun startCheckingUpdates() {
job?.cancel()
job = scope.launch { checkQueueUpdates() }
}
private suspend fun checkQueueUpdates() {
while (true) {
when (val item = updatesChannel.receive()) {
is Update -> handleUpdate(item)
is TelegramError -> handleError(item)
else -> Unit
}
yield()
}
}
因此,如果您有关于更新处理的最佳设计的建议,我将不胜感激。
您通常希望从使用结构化并发中受益。这意味着您不会在类级别单独创建协程作用域,而是在应用程序级别定义协程作用域,或者在 UI 框架作为应用程序的入口点时使用 UI 框架提供的协程作用域。所有其他协程和作用域都应以某种方式(直接或间接)启动,并将根作用域作为其父级。这样,当不再使用某些功能时,您始终可以取消作用域及其所有子项,包括它们的协程。
此外,挂起函数和协程应该为自己定义要为代码的哪些部分使用哪个调度程序。毕竟,他们最清楚自己要做什么以及哪个调度员最合适。当
launch
ed 时,可以为新协程提供上下文参数,挂起函数可以使用 withContext
来切换调度程序。
您可以使用一些预定义的调度程序,但最佳实践是通过封闭类的参数提供调度程序,这样您就可以轻松地将其切换到单元测试中。然而,主动切换到该调度程序仍然应该执行协程或挂起函数本身。
在不了解该函数实际功能的情况下,我无法判断给定的调度程序是否合适。但由于它似乎形成了某种类型的事件循环并且不会启动任何新的协程(据我所知),因此将其分配给具有多个线程的调度程序是毫无意义的。这不会有什么坏处,但也没有帮助,因为该挂起函数中的所有内容都是同步执行的,一个接一个。
当
updatesChannel
是 kotlinx.coroutines.channels.Channel
时,这种挂起循环是对传入事件做出反应的惯用方式。仅当一个线程无法跟上处理传入的事件时,多个线程才会有帮助。由于我怀疑事件涉及一些网络 IO,所以我希望 handleUpdate
可以轻松地在事件发生之前完成对一个事件的处理。下一篇到了。