作者:李辰1990 | 来源:互联网 | 2023-09-10 20:29
同步方式的代码大概是这样写(kotlin 伪代码)
var loginResult = accountRpc.login(userName, password)
if(!loginResult.success){
throw LoginException("用户名或密码错误")
}
var permission = rbacRpc.permission(loginResult.userId)
UserContext.setContext(permission)
异步方式写代码(伪代码):
//入参 loginPromise
accountRpc.login(userName, password) {
if (!it.success){
loginPromise.failed(it.cause)
}
rbac.permission(it.userId){ permission ->
UserContext.setContext(permission)
loginPromise.success()
}
}
基于非阻塞IO
进行编程,编程语言
分为了两种解题思路,一种基于eventloop加回调
(什么promise、reactive,说到底就是基于回调封装的一些模式),一种基于协程
eventloop + 回调
java就是典型代表, 代码逻辑都是运行在线程上的,java基于nio可以实现非阻塞IO
, 基于nio需要开发者注册一堆的handler,就是回调。
nio太难用, 就有大神写了netty,netty对nio、epoll甚至bio都做了统一化的api封装,简化了java网络编程。
后来业界又推出了reactive编程范式(此处不展开,感兴趣可以看下:Reactor2-93.pdf
)
以上可能是基于线程来解决异步编程的已知的比较不错的方案了,还是无法避免编程上的复杂度。
协程
协程,一种更轻量级的线程,是语言层面对执行动作
和线程
的一次解耦,此处说的是语言层面
,即这个抽象是做在编程语言层面,底层基于操作系统的线程,上层在进程内基于编程语言开发了自己的一套调度策略,封装出了一个叫做协程
的概念,这样做的好处是,开发者可以以同步的方式写异步的代码
,典型的代表:golang、kotlin;
golang是天生支持,支持的效果会让开发者感觉不到线程的存在,反过来想,也会让开发者越来越白痴(这又是一个权衡,语言太好了,开发者就...)
jvm生态里,kotlin也号称支持协程,不过由于历史包袱的原因,开发者还是会感觉到线程和协程,比如runBlocking
函数就是用来衔接线程和协程执行的, 此处贴一下函数注释:
Runs new coroutine and blocks current thread interruptibly until its completion
最近在下也一直在研究kotlin,我对这门语言还是持拥抱态度的,不只是协程,还有各种语法糖(相对于java来讲),可以减少一点开发工作量。
回到刚刚的话题往下聊,jvm体系里,能和golang相抗衡的协程方案,必须是要坐在jvm级别的,目前已知的是阿里的wisp
和openjdk的loom
这两种方案,都还没有深入了解过,不敢妄言。
异步编程的魅力
从本文最开始的一个故事开始,依次引出了c10k问题,然后又赘述了很多的解决之道,最后引出异步编程。按照这个套路来阐述,是因为本人神反感技术文档不讲解决什么问题,上来就抛出一大堆技术概念,在下喜欢从头讲故事。
现在可以聊一聊异步编程的魅力了,异步编程会比同步编程更复杂一些
基于此演进出了很多花里胡哨
的技术名词,对于一个有追求的开发人员,异步编程是必须要了解和运用的一种技术;
异步编程的魅力在哪,我个人是因为对这个陌生领域一知半解的时间太久了,就是要搞定这件事情。
c10k的问题,不仅仅是异步编程就可以解决的,“不谈存储层设计的高并发,都是耍流氓”,高并发是对整个分布式系统里全链路的挑战,除非整个系统简单,无状态。
后续
后续会写一系列的文章,包括异步编程里的 promise模式、reactor模式、协程等。
这不是一篇解决具体问题的文章,是一系列需要静下心来慢慢读的文章,是关于异步编程的一些思考和总结。
后续将会针对异步编程写关于三种异步编程模式的文章:
promise模式
https://www.jianshu.com/p/b3febf70c09e
reactor模式
https://www.jianshu.com/p/a248205d6eb2
协程
https://www.jianshu.com/p/0d1b0c8b20ed