3.actor模型的基本搭建(c#代码)

本文看了博客C# 实现 Actor并发模型 (案例版)_51CTO博客_actor并发模型,这里作为笔记用,该博客内容写的很详细,这里基本上没有改动。

首先,本文的目录如下:

3.actor模型的基本搭建(c#代码)_第1张图片

每个cs文件的代码都有详细的注释,具体代码如下:

1. IActor.cs代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApp3.core
{
    /// 
    /// 无锁并行编程模型(暂时用来处理串行任务,任务串行执行)
    /// 
    public interface IActor
    {

        bool AddMsg(object message); //增加消息

        Task Start(); // 启动服务

        bool Stop(int WaitingTimeout); // 停止服务运行,等待毫秒数

    }
}

2. Actor.cs代码

using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApp3.core
{
    public abstract class Actor : IDisposable, IActor
    {
        public string Name { get; set; }//名称

        public bool Active { get; private set; } // 是否启用

        public bool LongRunning { get; set; } = true; // 是否长时间运行。长时间运行任务使用独立线程,默认true

        public BlockingCollection MailBox { get; set; } // 处理的消息邮箱

        private Task _task; // 内置任务

        public Actor(string name)
        {
            Name = name;
            MailBox = new BlockingCollection();
        }

        // 开始任务
        public virtual Task Start()
        {
            if (Active) return _task;
            Active = true;
            // 启动异步
            if (_task == null)
            {
                lock(this)
                {
                    if (_task == null)
                    {
                        // Task.Factory.StartNew: 线程的使用
                        // 如果LongRunning为真,则返回 TaskCreationOptions.LongRunning,否则返回TaskCreationOptions.None
                        _task = Task.Factory.StartNew(DoActorWork, LongRunning ? TaskCreationOptions.LongRunning : TaskCreationOptions.None);
                    }
                }
            }
            return _task;
        }

        // 停止任务
        public virtual bool Stop(int WaitingTimeout = 100)
        {

            //BlockingCollection?.CompleteAdding()它的作用是通知集合不再接受新的元素添加。调用此方法后,尝试向集合中添加元素的操作将会抛出异常,并且当集合为空时,
            //尝试从集合中移除元素的操作不会等待,而是立即返回。
            MailBox?.CompleteAdding();
            Active = false;
            if (WaitingTimeout == 0 || _task == null) return true;

            return _task.Wait(WaitingTimeout);
        }

        // 给邮件添加消息
        public virtual bool AddMsg(object message)
        {
            // 自动开始
            if (!Active) { Start(); }
            if (!Active) { return false; }
            MailBox.Add(message);
            return true;
        }

        // 循环消息
        private void DoActorWork()
        {
            //BlockingCollection.IsCompleted:指集合是否已经完成添加并且是否已经消耗了所有数据。换句话说,它返回 true 的条件是集合已经调用了 CompleteAdding() 并且集合为空。
            //因此,IsCompleted 包含了集合为空的判断
            while(!MailBox.IsCompleted)
            {
                try
                {
                    //BlockingCollection.Take():用于从集合中移除并返回一个元素。如果集合为空,调用线程会被阻塞,直到集合中有元素可用。
                    var ctx = MailBox.Take();
                    var task = ProcessAsync(ctx);
                    if (task != null)
                    {
                        task.Wait();
                    }
                }
                catch(InvalidOperationException) { }
                catch (Exception ex)
                {
                    Console.WriteLine($"DoActorWork Error : {ex.Message}");
                }
            }
            Active = false;
        }

        // 处理消息
        // abstract:是定义了一个抽象类
        public abstract Task ProcessAsync(object msg);

        public void Dispose()
        {
            try {Stop(100); }
            catch (Exception) { }
            // BlockingCollection?.TryTake(out _):尝试从MailBox中移除一个元素。如果集合为空,该方法会立即返回false;如果集合不为空,则尝试移除一个元素并返回true。
            // 如果操作成功,还可以通过out参数获取移除的元素。
            while (MailBox?.TryTake(out _) == true) { }
            MailBox = null;
        }

    }
} 
  

3.WriteActor.cs代码

using ConsoleApp3.core;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApp3
{
    public class WriteActor: Actor
    {
        public WriteActor() : base(nameof(WriteActor)) { }

         处理信息
        public override Task ProcessAsync(object msg)
        {
            try { Console.WriteLine($"输出 {this.Name} :{msg}");}
            catch(Exception e) { Console.WriteLine($"业务处理异常:{e.Message}"); }
            return Task.CompletedTask;
        }
    }
}

4.AccumulationActor.cs代码

using ConsoleApp3.core;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApp3
{
    public class AccumulationActor : Actor
    {
        private int Count = 0;
        private IActor actor;
        public AccumulationActor(IActor actor) : base(nameof(AccumulationActor))
        {
            Count = 0;
            this.actor = actor;
            //Console.WriteLine(nameof(AccumulationActor)); // 输出基类名称
        }
        // 处理信息
        public override Task ProcessAsync(object msg)
        {
            try
            {
                var msgNumber = (int)(msg);
                Count += msgNumber;
                Console.WriteLine($"处理{this.Name} :{msg} ,累积总数:{Count}");

                if (Count >= 100)
                {
                    this.actor.AddMsg(Count);
                    Count = 0;
                }
            }
            catch(Exception e) { Console.WriteLine($"业务处理异常:{e.Message}"); }

            return Task.CompletedTask;
        }
    }
}

5.program.cs代码

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace ConsoleApp3
{
    class Program
    {
        static void Main(string[] args)
        {

            Console.Title = "Actor Demo of wang";

            //实现一个加法逻辑
            //a累加到100,就发送消息到 b里,让b 输出

            var write = new WriteActor();
            var User = new AccumulationActor(write);
            for (int i = 0; i < 20; i++) { User.AddMsg(i * 30); }

            Thread.Sleep(2000);
            write.Stop();
            User.Stop();
            //释放资源
            Console.WriteLine("示例完毕!");
            Console.ReadLine();
        }
    }
}

你可能感兴趣的:(其他,c#,开发语言)