参考资料
- akka官方文档,https://doc.akka.io/docs/akka/current/typed/guide/introduction.html
- akka官方中文文档,https://github.com/guobinhit/akka-guide/blob/master/README.md
- https://www.lightbend.com/akka/developers
- actor-fundamentals,https://akkademy.akka.io/learn/courses/21/actor-fundamentals
- https://www.zhihu.com/question/279512440
akka和netty的比较
从Akka出现背景来说,它是基于Actor的RPC通信系统,它的核心概念也是Message,它是基于协程的,性能不容置疑;基于scala的偏函数,易用性也没有话说,但是它毕竟只是RPC通信,无法适用大的package/stream的数据传输,这也是Spark早期引入Netty的原因
那么Netty为什么可以取代Akka?首先不容置疑的是Akka可以做到的,Netty也可以做到,但是Netty可以做到,Akka却无法做到,原因是在软件栈中,Akka相比Netty要Higher一点,它专门针对RPC做了很多事情,而Netty相比更加基础一点,可以为不同的应用层通信协议(RPC,FTP,HTTP等)提供支持,在早期的Akka版本,底层的NIO通信就是用的Netty
Spark基于这个思想在上述的Network的基础上实现一套自己的RPC Actor模型,从而取代Akka。其中RpcEndpoint对于Actor,RpcEndpointRef对应ActorRef,RpcEnv即对应了ActorSystem。
为什么现代系统需要新的编程模型解释了共享内存并发模型的缺点,通过消息传递实现协调
- actor = 状态+行为+消息
关于akka和erlang/OTP的比较
在 Akka 库中,Actor 是用 Scala 或 Java 编写的,并运行在一个 ActorSystem 中。Akka 使用一个事件驱动的调度器来确保 Actor 能够高效地并发执行。Actor通常由用户空间的库来调度和管理,而不是由操作系统内核来管理。这意味着 Actor 的上下文切换开销较低,并且可以在单个 JVM 实例中支持大量的 Actor
Erlang 的进程(Processes)实际上实现了与 Actor 模型非常相似的行为。实际上,Erlang 的进程模型可以被认为是 Actor 模型的一个实例化版
一般来说有两种策略用来在并发线程中进行通信:共享数据和消息传递。使用共享数据方式的并发编程面临的最大的一个问题就是数据条件竞争。和共享数据方式相比,消息传递机制最大的优点就是不会产生数据竞争状态。实现消息传递有两种常见的类型:基于channel(golang为典型代表)的消息传递和基于Actor(erlang为代表)的消息传递。https://zhuanlan.zhihu.com/p/86460724
两者都是通过消息通信的机制来避免竞态条件
- CSP的模式比较适合Boss-Worker模式的任务分发机制,侵入性没那么强,可以在现有的系统中通过CSP解决某个具体的问题。它并不试图解决通信的超时容错问题,需要发起方进行处理
- 使用Actor要面临整个应用架构机制和思维方式的变更,比如容错,比如分布式
Akka是在线程池基础上实现调度的,但线程是有限的,所以Akka的Actor中要避免任何阻塞操作,要么用Akka提供的异步框架,要么通过Future-callback机制,转换成回调模式。而Goroutine是用户态的线程,创建和切换成本都比较小,可以把异步的callback机制转换为同步模式,对开发比较友好些
并发之痛 Thread,Goroutine,Actor讨论
https://jolestar.com/parallel-programming-model-thread-goroutine-actor/
Go的Channel和Java中的SynchronousQueue是一样的机制,如果有buffer其实就是ArrayBlockQueue
Go实现了M:N的调度,也就是说线程和Goroutine之间是多对多的关系。这点在许多GreenThread/Coroutine的调度器并没有实现。Java1.1版本之前的线程其实是GreenThread(这个词就来源于Java),但由于没实现多对多的调度,也就是没有真正实现并行,发挥不了多核的优势,所以后来改成基于系统内核的Thread实现了。
java21引入和Virtual Threads新特性。虚拟线程是一种轻量级的线程,它适用于 I/O 密集型的任务。对于CPU密集型任务(如大量计算),平台线程可能是更好的选择