C#调用F#的MailboxProcessor

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锁效率接近,并可简化代码,避免加锁。

相关推荐
米优1 小时前
qt+vlc实现解码h264/h265裸码流播放
开发语言·qt·vlc
xyq20241 小时前
W3C CSS 活动
开发语言
Han_han9191 小时前
案例二:交通工具调度系统(核心:继承 + 多态 + final + 方法重写)
java·开发语言
沐知全栈开发1 小时前
CSS Float(浮动)
开发语言
小张-森林人1 小时前
电子病历文书编辑器 Demo
开发语言·c#
cch89181 小时前
Java vs 汇编:高级与低级的终极对决
java·开发语言·汇编
2301_789015621 小时前
C++:异常
开发语言·c++·异常·异常的处理方式
CVer儿1 小时前
c++接口内部内存分配问题设计
开发语言·c++
如若1231 小时前
ERROR:pdf2zh.converter:‘str‘ object has no attribute ‘choices‘ converter.py:357
java·开发语言·servlet
2301_789015621 小时前
C++:智能指针
c语言·开发语言·汇编·c++·智能指针