如何解决什么是相当于Executor服务的Android协程
我有一个ExecutorService
代码段,并且我试图将其转换为协程以测试性能。但是,无论我如何构造协程代码,ExecutorService
都快得多。我认为协程应该可以改善性能
功能:
- 在后台线程中运行
- 执行200000次操作(计数器++)
- 传递到UI线程的时间
- 代码在ViewModel中运行,以更新时间文本视图
- 执行器服务代码在模拟器上大约需要150毫秒
- 我编写的任何协程代码都需要更长的时间
协程相当于以下代码:
fun runCodeExecutorService() {
spinner.value = true
val executorService = Executors.newFixedThreadPool(NUMBER_OF_CORES * 2)
val result = AtomicInteger()
val startTime = System.currentTimeMillis()
val handler: Handler = object : Handler(Looper.getMainLooper()) {
override fun handleMessage(inputMessage: Message) {
time.value = toTime(System.currentTimeMillis() - startTime)
spinner.value = false
Log.d("tag","counter Executor = " + result.get())
}
}
thread(start = true) {
for (i in 1..NUMBER_OF_THREADS) {
executorService.execute {
result.getAndIncrement()
}
}
executorService.shutdown();
executorService.awaitTermination(2,TimeUnit.MINUTES)
val msg: Message = handler.obtainMessage()
val bundle = Bundle()
bundle.putInt("MSG_KEY",result.get())
msg.data = bundle
handler.sendMessage(msg)
}
}
其中NUMBER_OF_CORES是val NUMBER_OF_CORES = Runtime.getRuntime().availableProcessors()
NUMBER_OF_THREADS是200000
解决方法
调度程序大致等同于
suspend fun aLotOfCoroutines() {
spinner.value = true
val result = AtomicInteger()
val startTime = System.currentTimeMillis()
coroutineScope {
repeat(NUMBER_OF_THREADS) {
launch(Dispatchers.Default) { // 1
result.getAndIncrement()
}
}
} // 2
// 3
time.value = toTime(System.currentTimeMillis() - startTime)
spinner.value = false
Log.d("tag","counter Dispatchers.Default = " + result.get())
}
-
我们可以使用
Dispatchers.Default
来执行非阻塞任务,而不是创建和停止新的执行程序。 -
使用结构化并发,
coroutineScope
不会返回,直到其所有子协程完成。这就是为什么我们不需要显式等待完成的原因。 -
因为在
Dispatchers.Main
中调用了此方法,所以这些行也将在主线程中运行。
如果您确实要使用自定义线程池,则可以在执行程序上使用asCoroutineDispatcher
扩展方法。
在知道OP对性能数字感兴趣之后,我进行了更多调查。
在此“测试”中:
- 任务很便宜。因此,每个任务的开销非常明显。
- 此任务对资源的争夺非常激烈,以至于不进行并行化比较快。单线程运行需要1毫秒。
我认为可以说这与任何实际工作量都不一样。
无论如何,以下工作池与线程池的时间相似。
coroutineScope {
val channel = produce(capacity = 64) {
repeat(JOB_COUNT) { send(Unit) }
}
// The fewer workers we launch,the faster it runs
repeat(Runtime.getRuntime().availableProcessors() * 2) {
launch {
for (task in channel) {
result.getAndIncrement()
}
}
}
}
,
@George实际上您的代码正在阻塞,实际代码可能看起来像这样:
fun runCodeCoroutines() = viewModelScope.launch {
spinner.value = true
val result = AtomicInteger()
val startTime = System.currentTimeMillis()
withContext(Dispatchers.Default) {
result.aLotOfCoroutines()
}
// 3
time.value = toTime(System.currentTimeMillis() - startTime)
spinner.value = false
Log.d("tag","counter Dispatchers.Default = " + result.get())
}
suspend fun AtomicInteger.aLotOfCoroutines() {
coroutineScope {
repeat(NUMBER_OF_THREADS) {
launch(Dispatchers.Default) { // 1
getAndIncrement()
}
}
} // 2
}
其中aLotOfCoroutines是您的代码 这大概是我得到的结果。
基准: 协程代码〜1.2秒 执行程序代码〜150毫秒
还有另一个版本的代码,我将线程数分成200 * 1000
suspend fun massiveRun(action: suspend () -> Unit) {
coroutineScope { // scope for coroutines
repeat(NUMBER_OF_TASKS) {
launch {
repeat(NUMBER_OF_ACTIONS) { action() }
}
}
}
}
大约需要35-40毫秒 但是,执行器服务中的相同故障大约需要25-35毫秒
距离更近,但总体上还是更好的
我的结论是,在查看性能时,Executor Service的性能仍然比协同程序更高
和协程仅在语法上且精确性能不重要(例如网络调用等)时才更好
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。