bmpi-dev / bmpi.dev

blog for bmpi.dev

Home Page:https://www.bmpi.dev

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

编程语言是如何实现并发的之并发模型篇 · 构建我的被动收入

utterances-bot opened this issue · comments

编程语言是如何实现并发的之并发模型篇 · 构建我的被动收入

本文介绍多种并发模型包括锁、STM、CSP、Actor及I/O多路复用等,还有对Java、Go、Erlang/Elixir与Clojure等对这些模型的实现的介绍。

https://www.bmpi.dev/dev/deep-in-program-language/how-to-implement-concurrency/concurrency-model/

Actor模型和面向对象是两种东西,不能因为可以用面向对象处理就认为是面向对象。

Actor可以看做计算机世界里的 ‘人’,是一种针对并发的抽象,Actor模型=数据+行为+消息。Erlang最开始出现Actor,一切皆Actor,你能说Erlang是面向对象吗?不要搞混了概念。

Actor模型和面向对象是两种东西,不能因为可以用面向对象处理就认为是面向对象。

Actor可以看做计算机世界里的 ‘人’,是一种针对并发的抽象,Actor模型=数据+行为+消息。Erlang最开始出现Actor,一切皆Actor,你能说Erlang是面向对象吗?不要搞混了概念。

实际上面向对象的核心就是对象间通过消息来通信(smalltalk),只不过现在很多面向对象的语言都把重点放在了对象封装设计上了。Erlang的Actor真是很类似面向对象的通信上,两者都很类似。

Actor模型和面向对象是两种东西,不能因为可以用面向对象处理就认为是面向对象。
Actor可以看做计算机世界里的 ‘人’,是一种针对并发的抽象,Actor模型=数据+行为+消息。Erlang最开始出现Actor,一切皆Actor,你能说Erlang是面向对象吗?不要搞混了概念。

实际上面向对象的核心就是对象间通过消息来通信(smalltalk),只不过现在很多面向对象的语言都把重点放在了对象封装设计上了。Erlang的Actor真是很类似面向对象的通信上,两者都很类似。

面向对象的核心是一切皆对象,是一种编程模型和抽象方式吧?消息通信是通讯的一种方式,跟面向对象有什么关系呢?还是那句话,不能因为一个东西可以用面向对象实现出来,就把它叫面向对象,面向对象只是一种认知世界的模型。而Actor是另一种认知世界的模型。

拿汽车来说,面向对象就是把汽车当成一个对象(Car),Car还有一些属性,而所有数据的处理都是基于这个对象(Car)的,传参、进程间通信也是,消息通信的过程中也要传递一个对象,稍微复杂点的场景上只传递数据没多大意义,因为没有对象没有属性就没法处理。

在Actor模型下,汽车就是一个基本单元,它独立运行、不必具有属性、也必处理数据(可以只空转、不收/发外界信息)。而两个Actor(这两个Actor可以一个是人一个是汽车)之间只靠消息通讯来交换数据,交换的数据可以不具有任何特征、属性,只要两边能够相互识别即可。就像一个人可以远程遥控汽车,而不必非要把一个人的某些属性传过去,更不需要把人送过去(哪怕是复制的)。真正的Actor通信模型下,Actor不单单是世界组成的基本单元,还是运行的基本单元,并且不要求Actor都是一类。

拿汽车来说,面向对象就是把汽车当成一个对象(Car),Car还有一些属性,而所有数据的处理都是基于这个对象(Car)的,传参、进程间通信也是,消息通信的过程中也要传递一个对象,稍微复杂点的场景上只传递数据没多大意义,因为没有对象没有属性就没法处理。

在Actor模型下,汽车就是一个基本单元,它独立运行、不必具有属性、也必处理数据(可以只空转、不收/发外界信息)。而两个Actor(这两个Actor可以一个是人一个是汽车)之间只靠消息通讯来交换数据,交换的数据可以不具有任何特征、属性,只要两边能够相互识别即可。就像一个人可以远程遥控汽车,而不必非要把一个人的某些属性传过去,更不需要把人送过去(哪怕是复制的)。真正的Actor通信模型下,Actor不单单是世界组成的基本单元,还是运行的基本单元,并且不要求Actor都是一类。

在smalltalk的面向对象定义中核心是通过消息去通信,哪怕你去调用对象的一个方法,就是在发消息,所以这和actor模型是类似的。问题是现在的面向对象跑偏了,把重点放在了对象的封装设计上了,而忽略了消息通信。

顺便,面向对象这个概念也是 smalltalk 的作者提出的

commented

各位大佬,请教一下:

在netty eventloop中,一个连接所有的read,write操作都在一个线程中,也就是连接channel是和线程绑定的,这样,没有线程切换的问题,对一个连接来说也不需要共享内存,因为都在一个线程中。而在vertx 这样的actor模型中,为什么不把一个连接和线程绑定呢,比如,vertx作为http服务,接受一个请求,发出查询redis请求,查询的结果处理callback就不是在发出请求的线程了,这样会有线程切换,为什么actor实现是这样的。

如果我用netty作为http服务,接受请求,之后查询redis也是使用netty的编解码器,那么从接受http请求,到发出redis查询请求,再到redis返回结果处理,再把结果返回给客户端,整个流程都在一个线程中的,没有线程切换,数据共享的问题

actor模型跟netty的eventloop比哪种好?为什么?

原评论地址:

https://t.me/c/1264662201/253251

有些细节可以改进一下。创建线程并不比创建进程轻量多少(主要少了页表的复制,主要影响大内存进程);多线程相比多进程主要是通信方便。锁在竞争不激烈的情况下是很快的(比如 Rust 的锁会先自旋一下)。另外锁模型明明是最简单的模型(尤其是在 Rust 中少了很多误用的机会)。事件驱动也可以多线程以利用多核(如 tokio),它也会用到锁。

https://t.me/c/1264662201/253291

那现在不过是堆叠而已。线程间通信用共享内存和channel两种方式 可以理解。但并发模式里又出现event base模式 ,这又是根据消息/事件念引入的并发模式 与前面模型的关系都说清楚

https://t.me/c/1264662201/253305

每一个并发模式都是基于自己的概念范畴定义的 但既然要罗列所有的并发模式 那么就应该把他们的区别 给出来 我想的可能太理想 客观来说 对许多概念我也没厘清

https://t.me/c/1264662201/266403

(作者回复) 才看到,这篇文章有很多细节的错误,但这是因为我本身的局限导致,我的目的是想找一个统一的基线去对比不同网络并发模型的区别,因为很多时候开发者本身会受限自己了解的编程语言去设计方案,但在不同纬度的视角,同一个问题的解法也难以不同,这是我想表达的,但实际写作很难去把每个模型搞清楚,只能非常粗的做一个分类与对比

各位大佬,请教一下:

在netty eventloop中,一个连接所有的read,write操作都在一个线程中,也就是连接channel是和线程绑定的,这样,没有线程切换的问题,对一个连接来说也不需要共享内存,因为都在一个线程中。而在vertx 这样的actor模型中,为什么不把一个连接和线程绑定呢,比如,vertx作为http服务,接受一个请求,发出查询redis请求,查询的结果处理callback就不是在发出请求的线程了,这样会有线程切换,为什么actor实现是这样的。

如果我用netty作为http服务,接受请求,之后查询redis也是使用netty的编解码器,那么从接受http请求,到发出redis查询请求,再到redis返回结果处理,再把结果返回给客户端,整个流程都在一个线程中的,没有线程切换,数据共享的问题

actor模型跟netty的eventloop比哪种好?为什么?

eventloop 这种是利用多路复用的 I/O 模型去实现高并发,在请求被分发给 handler 后依旧可能利用多线程去处理代理请求(比如这个 request 里又请求了其他服务的 API ),所以并不是到 handler 之后就同步处理了,需要看实际的场景啊。actor 模型更复杂一些,但它可以跨节点去通信,适合分布式的场景。至于线程切换,如果是用户线程的话,切换开销不高,应该比同步等待 I/O 模型的数据开销都低。

为何 actor 模型要切换线程做,因为线程切换有开销。但 actor 模型的代表是 erlang 语言,erlang 实现了一个非常高效的用户线程调度模型,线程切换开销极低。