一、什么是Actor
Actor模型是1973年提出的一个分布式并发编程模式。在Actor模型中,Actor参与者是一个并发原语,简单来说,一个参与者就是一个工人,与进程或线程一样能够工作或处理任务。
二、Actor组成
1、状态(state)
指actor本身的属性信息,state只能被actor自己操作,不能被其他actor共享和操作,有效的避免加锁和数据竞争
2、行为(behavior)
指actor处理逻辑,如果通过行为来操作自身state
3、Mailbox邮箱
指actor存储消息的fifo队列,actor与actor发送消息,消息只能发送到邮箱,等待拥有邮箱的actor 去处理,这个过程是异步的。简单来说,有时间才处理,等我把前面任务先完成。
Actor模型遵循下面的规则:
所有的Actor状态是本地的,外部是无法访问的。
Actor必须通过消息传递进行通信
一个Actor可以响应消息、退出新Actor、改变内部状态、将消息发送到一个或多个Actor。
Actor可能会堵塞自己但Actor不应该堵塞自己运行的线程
三、场景举例
Actor模型用于处理多线程并发,锁,线程等一系列问题。
举一个例子:
现在有一个场景,要求用多线程实现“列出1~100的所有素数”。
那么我们的实现可能会是这样:
using System;
using System.Threading;
namespace CalPrime
{
public class Calculate
{
private int nowNum = 1; //当前计算的值
public void CalNum()
{
lock (this) //上锁,否则会出错
{
if (isPrime(nowNum))
Console.WriteLine($"{nowNum}");
nowNum ++;
}
}
private bool isPrime(int num) //计算是否素数
{
for (int i = 2; i <= MathF.Sqrt(num); i++)
{
if (num % i == 0)
return false;
}
return true;
}
}
class Program
{
static void Main(string[] args)
{
Calculate cal = new Calculate();
for (int i = 0; i < 100; i++) //多线程计算
{
Thread thread1=new Thread(new ThreadStart(cal.CalNum));//创建线程
thread1.Start();
}
}
}
}
可以看到,在上面的例子中,所有线程都会去访问变量nowNum。
1、如果我不对它进行上锁,限制访问,那么计算结果就会无法预知。(锁问题)
2、但加了锁以后,其他线程又必须等待该线程释放资源,这样又失去了多线程的意义。 (线程同步问题)
但如果用Actor模型来处理这个题目,就能避免上述的两个问题了。
具体思想是:
1、我不暴露变量nowNum变量,不让各个线程自行去获取。而是创建一个分发对象,由它持有nowNum,去给各个线程分发计算任务。
2、各个线程收到任务后,自行计算,再把结果发送给分发对象。
3、分发对象和各个线程对象之间采用邮件的形式沟通。