MailboxProcessor是单线程的简化Actor实现,在F#的dll类库中定义,C#中使用。
F#的库,需要从nuget下载FSharp.Core
cs
type CounterMessage =
| Increment of int
| GetCount of AsyncReplyChannel<int>
type CounterMailbox() =
let agent = MailboxProcessor<CounterMessage>.Start(fun inbox ->
let rec loop count = async {
let! msg = inbox.Receive()
match msg with
| Increment value -> return! loop (count + value)
| GetCount replyChannel -> replyChannel.Reply count
return! loop count
}
loop 0)
member this.Increment(value) = agent.Post(Increment value)
member this.GetCount() = agent.PostAndReply(GetCount)
member this.GetCountAsync() = Async.StartAsTask(agent.PostAndAsyncReply(GetCount))
cs
private CounterMailbox _counterMailbox;
private void Form1_Load(object sender, EventArgs e)
{
var myClass = new MyClass();
myClass.MyMethod();
_counterMailbox = new CounterMailbox();
}
private void button1_Click(object sender, EventArgs e)
{
_counterMailbox.Increment(1);
}
private async void button2_Click(object sender, EventArgs e)
{
var value = _counterMailbox.GetCount();
MessageBox.Show(value.ToString());
}
private async void button3_Click(object sender, EventArgs e)
{
var value = await _counterMailbox.GetCountAsync();
MessageBox.Show(value.ToString());
}
private int _cnt = 0;
private object _cntLock = new object();
private async void button4_Click(object sender, EventArgs e)
{
var stop = new Stopwatch();
stop.Start();
var taskList = new List<Task>();
for (var i = 0; i < 1000; i++)
{
var task = Task.Run(() => {
for (var j = 0; j < 10000; j++)
{
lock (_cntLock)
{
_cnt++;
}
}
});
taskList.Add(task);
}
await Task.WhenAll(taskList);
stop.Stop();
MessageBox.Show($"{stop.ElapsedMilliseconds}ms cnt={_cnt}");
}
private async void button5_Click(object sender, EventArgs e)
{
var stop = new Stopwatch();
stop.Start();
var taskList = new List<Task>();
for (var i = 0; i < 1000; i++)
{
var task = Task.Run(() => {
for (var j = 0; j < 10000; j++)
{
_counterMailbox.Increment(1);
}
});
taskList.Add(task);
}
await Task.WhenAll(taskList);
var cnt = _counterMailbox.GetCount();
stop.Stop();
//Thread.Sleep(2000);
MessageBox.Show($"{stop.ElapsedMilliseconds}ms cnt={cnt}");
}
private ConcurrentQueue<int> _incQueue = new ConcurrentQueue<int>();
private long _cntV3 = 0;
private async void button6_Click(object sender, EventArgs e)
{
CreateV3IncThread();
var stop = new Stopwatch();
stop.Start();
var taskList = new List<Task>();
for (var i = 0; i < 1000; i++)
{
var task = Task.Run(() => {
for (var j = 0; j < 10; j++)
{
_incQueue.Enqueue(1);
}
});
taskList.Add(task);
}
await Task.WhenAll(taskList);
var cnt = Interlocked.Read(ref _cntV3);
stop.Stop();
//Thread.Sleep(2000);
MessageBox.Show($"{stop.ElapsedMilliseconds}ms cnt={cnt}");
}
private Thread _v3Thread = null;
private void CreateV3IncThread()
{
if (_v3Thread != null)
return;
_v3Thread = new Thread(() =>
{
while (true)
{
if(_incQueue.TryDequeue(out int i))
Interlocked.Add(ref _cntV3, i);
else
Thread.Sleep(1);
}
})
{ IsBackground = true};
_v3Thread.Start();
}
耗时统计:
|----|----------|------|-------|---------|
| 序号 | 模式 | 线程数 | 线程内循环 | 耗时 |
| 1 | C# lock锁 | 1000 | 10000 | 240MS |
| 2 | Mailbox | 1000 | 10000 | 11117MS |
| 3 | 生产者消费者 | 1000 | 10000 | 1058MS |
| 4 | C# lock锁 | 1000 | 1000 | 26MS |
| 5 | Mailbox | 1000 | 1000 | 1082MS |
| 6 | 生产者消费者 | 1000 | 1000 | 82MS |
| 7 | C# lock锁 | 1000 | 100 | 5MS |
| 8 | Mailbox | 1000 | 100 | 95MS |
| 9 | 生产者消费者 | 1000 | 100 | 8MS |
| 10 | C# lock锁 | 1000 | 10 | 5MS |
| 11 | Mailbox | 1000 | 10 | 5MS |
| 12 | 生产者消费者 | 1000 | 10 | 3MS |
单线程的Actor模型在极高频更新情况下没有优势,单线程递归出现大量积压;在高并发低更新频率下和lock锁效率接近,并可简化代码,避免加锁。
