Kotlin 1.3:如何在单独的线程上执行块?

Kotlin 1.3: how to execute a block on a separate thread?

我一直在阅读有关 Kotlin 中的并发性的文章,并认为我开始理解它...然后我发现 async() 在 1.3 中已被弃用,我又回到了起点。

这是我想做的事情:创建一个线程(不幸的是,它必须是一个线程而不是一个托管池),然后能够在该线程上执行异步块,并且 return Deferred 个实例让我使用 .await().

在 Kotlin 中执行此操作的推荐方法是什么?

如消息中所述,不赞成使用 GlobalScope.async {} 等显式范围调用 async

这也是弃用方法的实际实现。

通过删除顶级 async 函数,您将不会 运行 陷入隐式范围或错误导入的问题。

让我推荐这个解决方案:

它将任务并行化为 3 个后台线程(所谓的 "triplets pool"),但很容易根据您的要求将其更改为单线程,方法是将 tripletsPool 替换为 backgroundThread,如下所示:

private val backgroundThread = ThreadPoolExecutor(1, 1, 5L, TimeUnit.SECONDS, LinkedBlockingQueue())

1。单线程协程调度程序

Here's what I'd like to do: create a thread (and it does have to be a thread rather than a managed pool, unfortunately)

只有当您准备深入研究并为这种情况实施您自己的协程调度程序时,启动一个原始线程来处理您的协程才是一个选择。 Kotlin 通过包装在调度程序中的单线程执行程序服务为您的需求提供支持。请注意,如果您使用采用线程工厂的重载,您仍然可以几乎完全控制如何启动线程:

val threadPool = Executors.newSingleThreadExecutor {
    task -> Thread(task, "my-background-thread")
}.asCoroutineDispatcher()

2。 async-await 对比 withContext

and then be able to execute async blocks on that thread, and return Deferred instances that will let me use .await().

确保您确实需要 async-await,这意味着您需要它来做其他事情而不是

val result = async(singleThread) { blockingCal() }.await()

仅当您需要启动后台任务时使用 async-await,在调用线程上做一些更多的事情,然后才 await() 在它上面。

大多数刚接触协程的用户都喜欢这种机制,因为它熟悉其他语言,并将其用于像上面这样的普通顺序代码,但避免了阻塞 UI 线程的陷阱。 Kotlin 有一个 "sequential by default" 哲学,这意味着你应该使用

val result = withContext(singleThread) { blockingCall() }

这不会在后台线程中启动新的协程,而是将当前协程的执行转移到它上面,并在完成后返回。

3。已弃用顶级 async

Then I discovered that async() has been deprecated in 1.3

产生免费的-运行后台任务通常是一种不合理的做法,因为它在出现错误或什至只是不寻常的执行模式时表现不佳。您的调用方法可能 return 或在没有 await 结果的情况下失败,但后台任务将继续。如果应用程序反复重新输入生成后台任务的代码,您的 singleThread 执行程序队列将无限增长。所有这些任务都将 运行 没有目的,因为他们的请求者早已不复存在。

这就是 Kotlin 弃用顶级协程构建器的原因,现在您必须使用 协程范围 明确限定它们,您必须根据您的用例定义其生命周期。当作用域的生命周期 运行 结束时,它将自动取消在其中生成的所有协程。

在 Android 的示例中,这相当于将协程范围绑定到 Activity 的生命周期,如 CoroutineScope.

的 KDoc 中所述