multithreading - 如何将协程直接分派(dispatch)到 JVM 上的主线程?

标签 multithreading kotlin kotlin-coroutines coroutinescope

我正在为 jvm 设置一个基于 kotlin 协程的网络框架。 Client 和 Server 类实现 CoroutineScope,并且 coroutinecontext 的重写是 Dispatchers.IO,因为我非常确定这是用于这种情况的正确 Dispatcher。但是,我希望在主线程上处理读取数据包,或者至少提供该选项。在没有阅读文档的情况下,我使用了 Dispatchers.Main,我现在意识到它是针对 android UI 线程的。是否有一个调度程序可以用来让协程在主线程上运行?如果没有,我该如何制作呢?

我查看了 kotlin 文档,了解如何创建基于单个线程的调度程序,但除了创建新线程的 newSingleThreadContext 之外,我找不到任何内容。我还发现可以从 java 执行器创建调度程序,但我仍然不确定如何将其限制为已经存在的线程。

class AbstractNetworkComponent : CoroutineScope {
    private val packetProcessor = PacketProcessor()
    private val job = Job()
    override val coroutineContext = job + Dispatchers.IO
}

class PacketProcessor : CoroutineScope {

    private val job = Job()
    override val coroutineContext = job + Dispatchers.Main //Android only!
    private val packetHandlers = mutableMapOf<Opcode, PacketHandlerFunc>()

    fun handlePacket(opcode: Opcode, packet: ReceivablePacket, networker: Writable) {
        launch(coroutineContext) {
            packetHandlers[opcode]?.invoke(packet, networker)
        }
    }
}

因此,在 Dispatchers.Main 中,由于缺少 android 组件,我收到了 IllegalStateException 异常。有没有办法创建一个调度程序来阻塞主线程直到其完成(就像 runBlocking 那样?)谢谢!

最佳答案

runBlocking 正是您所需要的。它创建一个调度程序并将其设置在协程上下文中。您可以通过以下方式访问调度程序

coroutineContext[ContinuationInterceptor] as CoroutineDispatcher

然后您可以将其传递给实现 CoroutineScope 的对象或您想要用它执行的任何其他操作。这是一些示例代码:

import kotlinx.coroutines.*
import kotlinx.coroutines.Dispatchers.IO
import kotlin.coroutines.ContinuationInterceptor

fun main() {
    println("Top-level: current thread is ${Thread.currentThread().name}")
    runBlocking {
        val dispatcher = coroutineContext[ContinuationInterceptor]
                as CoroutineDispatcher
        ScopedObject(dispatcher).launchMe().join()
    }
}

class ScopedObject(dispatcher: CoroutineDispatcher) : CoroutineScope {
    override val coroutineContext = Job() + dispatcher

    fun launchMe() = launch {
        val result = withContext(IO) {
            "amazing"
        }
        println("Launched coroutine: " +
                "current thread is ${Thread.currentThread().name}, " +
                "result is $result")
    }
}

这将打印

Top-level: current thread is main
Launched coroutine: current thread is main, result is amazing

关于multithreading - 如何将协程直接分派(dispatch)到 JVM 上的主线程?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54191538/

相关文章:

android - java.util.NoSuchElementException 导致找不到符号类 DataBindingComponent

android - 如何使用来自不同 DAO 的函数并使用协程与 Room 进行数据库事务?

android - 为什么 viewModelScope 在其子级失败时会自行取消?

C#:在 ASP.NET 中向 Parallel.ForEach() 添加上下文

c - 在linux中调度两个线程两个打印数字模式

android - Kotlin - 接口(interface)中的只读属性

spring - 自动重试请求的http代码是什么?

android - LifecycleScope.launchWhenStarted 是否安全?如果不安全,在什么情况下?

c# - 有趣的 Lucene.net 异常

c++ - 可以在调用构造函数之前完成赋值吗?