- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我是一名从 Java 转向 Kotlin 的 Android 开发人员,我打算使用协程来处理异步代码,因为它看起来很有前途。
回到 Java,为了处理异步代码,我使用 Executor
类在远离 UI 线程的另一个线程中执行一段耗时的代码。我在我的 xxxRepository
类中注入(inject)了一个 AppExecutors
类来管理一组 Executor
。它看起来像这样:
public class AppExecutors
{
private static class DiskIOThreadExecutor implements Executor
{
private final Executor mDiskIO;
public DiskIOThreadExecutor()
{
mDiskIO = Executors.newSingleThreadExecutor();
}
@Override
public void execute(@NonNull Runnable command)
{
mDiskIO.execute(command);
}
}
private static class MainThreadExecutor implements Executor
{
private Handler mainThreadHandler = new Handler(Looper.getMainLooper());
@Override
public void execute(@NonNull Runnable command)
{
mainThreadHandler.post(command);
}
}
private static volatile AppExecutors INSTANCE;
private final DiskIOThreadExecutor diskIo;
private final MainThreadExecutor mainThread;
private AppExecutors()
{
diskIo = new DiskIOThreadExecutor();
mainThread = new MainThreadExecutor();
}
public static AppExecutors getInstance()
{
if(INSTANCE == null)
{
synchronized(AppExecutors.class)
{
if(INSTANCE == null)
{
INSTANCE = new AppExecutors();
}
}
}
return INSTANCE;
}
public Executor diskIo()
{
return diskIo;
}
public Executor mainThread()
{
return mainThread;
}
}
然后我就可以在我的 xxxRepository
中编写这样的代码了:
executors.diskIo().execute(() ->
{
try
{
LicensedUserOutput license = gson.fromJson(Prefs.getString(Constants.SHAREDPREF_LICENSEINFOS, ""), LicensedUserOutput.class);
/**
* gson.fromJson("") returns null instead of throwing an exception as reported here :
* https://github.com/google/gson/issues/457
*/
if(license != null)
{
executors.mainThread().execute(() -> callback.onUserLicenseLoaded(license));
}
else
{
executors.mainThread().execute(() -> callback.onError());
}
}
catch(JsonSyntaxException e)
{
e.printStackTrace();
executors.mainThread().execute(() -> callback.onError());
}
});
效果非常好,谷歌甚至在他们的许多 Github Android repo 示例中都有类似的东西。
所以我在使用回调。但现在我厌倦了嵌套回调,我想摆脱它们。为此,我可以在我的 xxxViewModel
中编写,例如:
executors.diskIo().execute(() ->
{
int result1 = repo.fetch();
String result2 = repo2.fetch(result1);
executors.mainThread().execute(() -> myLiveData.setValue(result2));
});
USAGE 与 Kotlin 协程的用法有何不同?据我所见,它们最大的优势是能够以顺序代码风格使用异步代码。但是我可以使用 Executor
做到这一点,正如您从上面的代码示例中看到的那样。那我在这里错过了什么?从 Executor
切换到 Coroutines 会有什么好处?
最佳答案
好吧,协程更常被比作线程,而不是你在给定线程池上运行的任务。 Executor 略有不同,因为您拥有管理线程和排队任务以在这些线程上执行的东西。
我还要承认,我使用 Kotlin 的 courotines 和 actors 才大约 6 个月,但让我们继续。
异步 IO
所以,我认为一个很大的区别是,如果 IO 任务是一个真正的异步 IO 任务,在 IO 任务时正确地产生控制权,那么在协程中运行你的任务将允许你在单个线程上实现 IO 任务的并发仍在完成。您可以通过这种方式使用协程实现非常轻量级的并发读/写。您可以启动 10,000 个协程,所有协程都在 1 个线程上同时从磁盘读取,并且它会同时发生。您可以在此处阅读有关异步 IO 的更多信息 async io wiki
另一方面,对于 Executor 服务,如果您的池中有一个线程,您的多个 IO 任务将在该线程上依次执行和阻塞。即使您使用的是异步库。
结构化并发
借助协程和协程作用域,您会得到一种称为结构化并发的东西。这意味着您不必对正在运行的各种后台任务进行簿记,这样您就可以在进入某些错误路径时正确地清理这些任务。与您的遗嘱执行人一起,您需要跟踪您的 future 并自己进行清理。这是一篇由 kotlin 团队领导撰写的非常好的文章,充分解释了这种微妙之处。 Structured Concurrency
与 Actor 的互动
另一个可能更利基的优势是,通过协程、生产者和消费者,您可以与 Actors 进行交互。 Actors封装状态,通过通信而不是通过传统的同步工具实现线程安全的并发。使用所有这些,您可以以非常少的线程开销实现非常轻量级和高度并发的状态。 Executors 只是不提供与 Actor 之类的同步状态交互的能力,例如 10000 个线程甚至 1000 个线程。你可以愉快地启动 100 000 个协程,如果任务在适当的时间点挂起和让步控制,你可以取得一些出色的成绩。您可以在此处阅读更多信息 Shared Mutable state
重量轻
最后,为了演示轻量级协程并发性有多好,我会挑战你在执行器上做这样的事情,看看总耗时是多少(在我的机器上这在 1160 毫秒内完成):
fun main() = runBlocking {
val start = System.currentTimeMillis()
val jobs = List(10_000){
launch {
delay(1000) // delays for 1000 millis
print(".")
}
}
jobs.forEach { it.join() }
val end = System.currentTimeMillis()
println()
println(end-start)
}
可能还有其他的东西,但正如我所说,我还在学习。
关于java - Kotlin 的 Coroutines 与 Android 中的 Java Executor 有何不同?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55637016/
我正在查看Kotlin Github page我注意到 Kotlin 语言本身大部分是用 Kotlin 编写的:我只是想知道,一种语言怎么可能大部分都是用它自己的语言编写的?在您可以使用正在创建的语言
我有以下非常简单的 kotlin 代码来演示中缀函数 com.lopushen.demo.presentation 包 fun main(args: Array) { print("Hello
我在 Java 中有 2 个模型类,其中一个扩展了另一个 @UseStag public class GenericMessages extends NavigationLocalizationMap
Kotlin 代码 runBlocking { flow { for (i in 0..4) { println("Emit $i")
这三个 Kotlin 插件和它们的实际作用有什么区别? plugins { id 'kotlin-android' id 'org.jetbrains.kotlin.android'
我正在为某些现有库添加 Kotlin 原生 linuxX64 目标支持。库已成功编译,但在运行测试用例时,出现以下运行时错误: kotlin.native.concurrent.InvalidMuta
关闭。这个问题需要details or clarity .它目前不接受答案。 想改进这个问题吗? 通过 editing this post 添加细节并澄清问题. 关闭 2 年前。 Improve t
我创建了一个类并向其添加了一个与成员函数具有相同签名的扩展,并执行了这个方法,它总是执行成员方法。 class Worker { fun work() = "...working" } fun
我知道传递给函数的参数将被视为“val”,即使变量被初始化为“var”。但这对我来说一直是个问题。在下面的示例代码中,我想通过使用函数“changeNum”修改变量“num”的值。但当然,Kotlin
现在,我正在尝试用 Kotlin 重写我的 Java 应用程序。然后,我遇到了日志语句,比如 log.info("do the print thing for {}", arg); 所以我有两种方法可
有点出名article关于许多语言的异步编程模型的状态,指出它们存在“颜色”问题,特别是将生态系统分为两个独立的世界:异步和非异步。以下是这种语言的属性: 每个函数都有一种颜色,红色或蓝色(例如asy
因为 KDoc 文档生成引擎是 abandoned in favor of Dokka , Kotlin 文档应该称为“KDoc 注释”,还是“Dokka 注释”? 最佳答案 如所述here , KD
我想在可空对象上传递函数引用。以 Android 为例,假设我想使用 Activity#onBackPressed来自作为该事件的子级的片段。 如果我想调用这个函数,我可以很容易地做到 activit
我有一个列表 (x, y)其中y只能是 0 或 1 这样 例如: [(3, 0), (3, 1), (5, 1)] [(5, 0), (3, 1), (5, 1)] [(1, 1), (3, 1),
从强类型语言的定义来看: A strongly-typed programming language is one in which each type of data (such as intege
这不能编译的事实是否意味着它们不是一流的类型? fun foo(s: String): Int = s.length // This won't compile. val bar = foo 有没有办
如果在 Java i++是一个表达式和 i++;是一个表达式语句,分号(;) 在 Kotlin 中是可选的,是 i++ Kotlin 中的表达式或表达式语句? 最佳答案 i++是一个表达式,因为它有一
代码(如下所示)是否正确?它取自 Kotlin-docs.pdf 的第 63 页,这也是 https://kotlinlang.org/docs/reference/generics.html 的最后
我正在尝试使用 Kotlin 为 Android 的一些全局 API 解析器(检查网络连接、调用 API 并通过来自源的单个调用返回格式化数据),并且在某些时候我不得不创建一个通用类型 object就
kotlinlang 中的任务: 使用月份变量重写此模式,使其与格式 13 JUN 1992(两位数字、一个空格、一个月份缩写、一个空格、四位数字)中的日期相匹配。 答案是:val month = "
我是一名优秀的程序员,十分优秀!