Actor model

 

 

C++ Actor框架

 

http://www.aiuxian.com/relative/p-1940333.html

通过akka, erlang来了解actor模型

c++并发编程的一种思维

使用笔记博客

https://www.cnblogs.com/zhejiangxiaomai/p/5257057.html

https://blog.csdn.net/woshiyuanlei/article/details/51276369

actor模型的优缺点分析

 

0x00 前言

一般来说有两种策略用来在并发线程中进行通信:共享数据和消息传递。熟悉c和java并发编程的都会比较熟悉共享数据的策略,比如java程序员就会常用到java.util.concurrent包中同步、锁相关的数据结构。

 

使用共享数据方式的并发编程面临的最大的一个问题就是数据条件竞争(data race)。处理各种锁的问题是让人十分头痛的一件事。

 

和共享数据方式相比,消息传递机制最大的优点就是不会产生数据竞争状态(data race)。实现消息传递有两种常见的类型:基于channel的消息传递和基于Actor的消息传递。本文主要是来分享Scala的Actor模型。

 

文章结构

本篇博客尝试讲解Actor模型。由于目前Scala的使用频率较高,因此主要语言为Scala

 

主要分为下面几个部分:

Actor模型的基本概念使用

讲一下akka框架中scala的基本使用,主要提几个重要的api

写几个例子帮助理解 

1. HelloWorld 简单版:通过这个例子来简单看一下AkkaActor的使用 

2. HelloWordl 进阶版:稍微进化了一点点,多了preStartPoisonPill的使用。 

3. WordCount 伪分布式:一个单机版的wordcount,一个map,多个reduce。后续再补充完全分布式的程序。

0x01 基本概念

Actor是计算机科学领域中的一个并行计算模型,它把actors当做通用的并行计算原语:一个actor对接收到的消息做出响应,进行本地决策,可以创建更多的actor,或者发送更多的消息;同时准备接收下一条消息。

 

在Actor理论中,一切都被认为是actor,这和面向对象语言里一切都被看成对象很类似。但包括面向对象语言在内的软件通常是顺序执行的,而Actor模型本质上则是并发的。

 

什么是Actor模型

Actor的概念来自于Erlang,在AKKA中,可以认为一个Actor就是一个容器,用以存储状态、行为、Mailbox以及子ActorSupervisor策略。Actor之间并不直接通信,而是通过Mail来互通有无。

 

每个Actor都有一个(恰好一个)Mailbox。Mailbox相当于是一个小型的队列,一旦Sender发送消息,就是将该消息入队到Mailbox中。入队的顺序按照消息发送的时间顺序。Mailbox有多种实现,默认为FIFO。但也可以根据优先级考虑出队顺序,实现算法则不相同。

 

消息和信箱

异步地发送消息是用actor模型编程的重要特性之一。消息并不是直接发送到一个actor,而是发送到一个信箱(mailbox)。如下图。

 

这样的设计解耦了actor之间的关系——actor都以自己的步调运行,且发送消息时不会被阻塞。虽然所有actor可以同时运行,但它们都按照信箱接收消息的顺序来依次处理消息,且仅在当前消息处理完成后才会处理下一个消息,因此我们只需要关心发送消息时的并发问题即可。

--------------------- 

作者:木东居士 

来源:CSDN 

原文:https://blog.csdn.net/zhaodedong/article/details/73441303 

版权声明:本文为博主原创文章,转载请附上博文链接!

 

https://blog.csdn.net/kjfcpua/article/details/8147850

 

其他c++ actor库

orca

https://segmentfault.com/a/1190000016955361?utm_source=tag-newest

theron

https://blog.csdn.net/FX677588/article/details/74936625

http://www.mahaixiang.cn/bcyy/954.html

 

actormodel概念介绍,这个文章比较好,讲了actorrpcmq系统的一点点联系

http://www.sohu.com/a/306231390_684445

回去好好看看,总结!

https://blog.csdn.net/yongche_shi/article/details/51523688

 

https://stackoverflow.com/questions/51904706/check-whether-a-detached-pthread-is-still-alive/51915501?r=SearchResults#51915501

对于使用actor model的建议

问题说,需要一个独立的线程,detached。

说自己使用c++,问为什么不用c++的标准线程库,然后说大家都在用pthread,而且切换到C时候也不用改代码

然后推荐用条件变量

 

然后的一个回答就有深度了,推荐使用actor model,然后在回答中说。

如果你想让一些线程独立工作并且不管它,那么适合使用actor model。介绍说0mqsocket其实不仅仅是unix socket,也可以是tcp socketipcimprocess-transfer,但是行为都是一致的,而且,in-proc memory transfer真的很快

Actor modelCSP Communicating Sequential Processes)的区别就是。在actor模式中,当一个消息送达,sender不会受到额外信息。但是在CSP中,一个成功的send,需要接收方收到消息并且读取消息。

在实践actorCSP编程中,不要混用各种并发机制,即不要使用共享内存,信号,条件变量等其他机制,非常容易混淆。(z项目已经彻底腐坏)

A------Have you thought about using Actor model programming, or even better Communicating Sequential Processes?

These are really quite a good model for when you have a separate thread that needs to go off and do its own thing, and you need to be able to tell it something and get an answer back.

Your apparent need is to know that something asynchronous has completed (the termination of a separate thread) - there's nothing wrong with having that thread send you a direct acknowledgement of it's termination, rather than trying to have to determine whether or not it's still alive through slightly iffy means such as waitpid(). So say you chose ZeroMQ as your Actor model library; to "kill" that detached thread you'd send it a command down a ZeroMQ "socket". The recipient thread would receive that message, understand that it means "die", and do whatever clean up it needs to before terminating itself. Just before it terminates itself, it sends you back an acknowledgement on another "socket" that yes, it is dead (or at least about to be so, all necessary cleanup has already happened).

Actor model / CSP programming places an emphasis on having a loop responding to messages from one or more sources. Well, your own code snippet hints at a loop, waiting for the pthread_cancel()to take effect.

I've put "socket" in quotes as underneath a ZeroMQ socket can be a tcp socket, ipc, some in-process memory transfer, etc; it all behaves the same. In-proc is, naturally, quite quick.

The difference between Actor model and Communicating Sequential Processes is that in Actor model, when a message is sent there is no information available to the sender that it has been received, whilst in Communicating Sequential Processes a successful send = a completed read. Personally speaking I prefer the latter - your code then has complete knowledge as to where a message recipient has got to; a send/receive are an Execution Rendezvous. So when you send the "terminate" message, you know for sure that the recipient thread has received the message and is now acting on it. When the recipient sends it's "I'm dead" acknowledgement, it knows that the command thread has received that ack.

FYI, CSP is very useful in real time systems, not because it's faster but because your program can have much better knowledge as to whether it's kept up with the real time demand or not. Actor model lets you "hide" real time inadequacies as latency in communications links.

Thank you for answering the actual question and for the great advice. Jonathan Lee Aug 19 '18 at 18:50

@JonathanLee, no worries, good luck! Be aware that if you are going to go with Actor model or CSP programming, it's best if you go the whole way. That is, don't try and casually mix it with shared memory, signals, or condition variables; it can get horribly confusing (especially signals; yeurk!). That total conversion might be a major revision to the architecture of your application, so it's worth doing some reading and careful thinking about the architecture. As you're detaching a thread I suspect that actually there's not too much data being shared between them, so perhaps it's not too bad. bazza Aug 20 '18 at 23:45

@JonathanLee, p.s. good reading material for ZeroMQ can be found by searching for the ZeroMQ guide. bazza Aug 20 '18 at 23:46

@JonathanLee, p.p.s. (sorry!), CSP is making something of a comeback. Both Rust and Golang have it as part of the language. Rust in particular is looking very good, with many of the beneficial aspects of C++ plus a whole load of strict memory safety thingies (you can tell I've not started learning it yet...). I suspect that the CSP is a side effect of the way it controls memory, much as CSP involves "copying" data from A to B; passing "ownership" of data from A to B achieves much the same thing without the actual copying taking place. bazza Aug 20 '18 at 23:48 

 

 

 

Q----I am working with POSIX threads for a multi-threaded socket programming project. I have run into a situation where I need to detach a thread from the main program using setdetachstate(); however, later on I cancel the thread (I know that cancelling is generally bad practice, but I know what I'm doing (hopefully)). I need a method to check whether the thread is still alive or not, and after doing a bit of research, I found that waitpid() might work for my purposes even though I have a TID instead of a PID. However, after trying it out, both with and without ptraces, it didn't work. Another method that I have seen on the Internet everywhere is pthread_join(). While I agree that it is the optimal way to do it, as I said, my thread is detached, so it can't be joined.

As a side note, my goal is to find a way to wait for the function call pthread_cancel() to finish before executing any subsequent code, i.e.

pthread_t tid; // ... pthread_cancel(tid); // wait until pthread with ID tid is cancelled // more code here...

Originally, the reason why I need to check whether the detached pthread is alive was because I was planning on doing something like this: while(!pthread_dead(tid)); or something of this manner; however, if there is a solution that directly waits for the cancel to finish, that would be even better. Please try not to criticize my use of detached threads or pthread cancelling; I have contemplated many plans of action and this seems to be required no matter how I go about it (unless I'm doing a multiprocessed application, which I don't want to do). Unless I'm doing something absolutely syntactically or structurally abominable, I would appreciate it if you just answered my question.

Thank you!

P.S. I'm coding in C++.

 

"P.S. I'm coding in C++." So why not using the C++ standard threading facilities instead of native pthread funcitonality? πάντα ε Aug 18 '18 at 2:23

άνταε It seems that pthreads are used the most in C++ socket programming, at least in the books and people that I've talked to. And, I think it has better documentation and community than std::thread. There was a time that I was thinking of using it though. Also, if I ever go back to C for some reason or another, I won't have to change it. Jonathan Lee Aug 18 '18 at 2:26 

Did you consider using a condition variable to negotiate the termination of the thread? Galik Aug 18 '18 at 2:33

@JonathanLee Regarding documentation I can't agree with your argument. The native pthread lib implementations might consider some specific OS functionality but usually isn't abstract enough to exhaust any aspect of facilities the particular OS offers. I'd just rely on some good abstractions of synchronization mechanisms as the C++ standard library offers. πάντα ε Aug 18 '18 at 2:35 

2

A condition variable allows one thread to send signals to another thread that a condition has changed. Using a condition variable you can set a condition for the thread to stop and that thread can then signal you when it has completed. Galik Aug 18 '18 at 2:40

 

actor模型与DDD的一些思路碰撞

https://www.jdon.com/45516

>1.actor并发模型的应用场景?

 

适合有状态或者称可变状态的业务场景,如果用DDD术语,适合聚合根,具体案例如订单,订单有状态,比如未付款未发货,已经付款未发货,已付款已发货,导致订单状态的变化是事件行为,比如付款行为导致顶大状态切换到"已经付款未发货"。

 

如果知晓GOF设计模式的状态模式,就更好理解有态概念。

 

2.actor的原理?思维方式改变?

 

行为导致状态变化,行为执行是依靠线程,比如用户发出一个付款的请求,服务器后端派出一个线程来执行付款请求,携带付款的金额和银行卡等等信息,当付款请求被成功完成后,线程还要做的事情就是改变订单状态,这时线程访问订单的一个方法比如changeState。

 

如果后台有管理员同时修改这个订单状态,那么实际有两个线程共同访问同一个数据,这时就必须锁,比如我们在changeState方法前加上sychronized这样同步语法。

 

使用同步语法坏处是每次只能一个线程进行处理,如同上厕所,只有一个蹲坑,人多就必须排队,这种情况性能很低。

 

如何避免锁?

 

避免changeState方法被外部两个线程同时占用访问,那么我们自己设计专门的线程守护订单状态,而不是普通方法代码,普通方法代码比较弱势,容易被外部线程hold住,而我们设计的这个对象没有普通方法,只有线程,这样就变成Order的守护线程和外部访问请求线程的通讯问题了。

 

Actor采取的这种类似消息机制的方式,实际在守护线程和外部线程之间有一个队列,俗称信箱,外部线程只要把请求放入,守护线程就读取进行处理。

 

这种异步高效方式是Actor基本原理,以ERlang和Scala语言为主要特征,他们封装得更好,类似将消息队列微观化了。

 

我个人认为要使用好Actor,还是要树立自己对有态和无态的敏感性,这是几年前我宣传EJB的有态和无态Bean强调的一点,如果没有这个敏感性,按照DDD第一找出聚合根的分析方法也能抓住重点。

 

当然这些思维的前提是抛弃数据库中心思维,不要老是想着把状态存在数据库中,然后用SQL不断修改,这是很低效的,也是有锁,比Java等语言的同步锁性能更差。

 

以我个人来说经历的步骤如下:

 

1.用数据表一个字段来表示状态,比如1表示已付款未发货,2表示已付款已发货,然后用户来一个请求用SQL修改。

 

2.ORM实现,比如Hibernate JPA来修改状态,虽然不用SQL了,但是Hibernate的悲观锁和乐观锁也让人抓狂。

 

3.彻底抛弃数据库,直接在内存缓存中进行修改,使用Java的同步锁,性能还是不够,吞吐量上不去。

 

4.Actor模型。


posted @ 2019-07-01 23:07  哈骑士  阅读(1359)  评论(0编辑  收藏  举报