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 中所述
我一直在阅读有关 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
.