首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> 關於.NET

ActorLite:輕量級 Actor 模型實現(中)—— 核心調度邏輯與 C# 完整實作

     編輯:關於.NET

承接上篇,本文將呈現一個簡單但功能完整的 Actor 模型核心實作。採用事件驅動分派,直接利用 .NET 內建線程池執行任務。關鍵在於兩大原則:訊息存在即儘早執行、單一 Actor 訊息循序執行。由此衍生兩個將 Actor 推入線程池的時機:收到訊息且 Actor 處於等待狀態、執行完訊息且信箱仍有訊息。並發控制稍有不慎即會導致 Actor 卡死、重複執行或空跑,文中將逐步拆解無鎖同步機制。

Actor 抽象介面與內部協定

對外暴露三個核心功能:投遞訊息(Post)、處理訊息(Receive)、退出迴圈(Exit)。內部則透過 IActor 介面統一調度:

internal interface IActor
{
    void Execute();
    bool Existed { get; }
    int MessageCount { get; }
    ActorContext Context { get; }
}

ActorContext 封裝同步所需的原始欄位(如 m_status),避免對屬性/方法進行 CAS 操作的限制,同時解決 F# 存取基類 internal 成員的 Bug。

狀態機與無鎖分派

Actor 三態:WAITING (0)、EXECUTING (1)、EXITED (2)。Dispatcher.ReadyToExecute 以 Interlocked.CompareExchange 原子性地將狀態從 WAITING 切為 EXECUTING,成功才將 Actor 推入線程池:

public void ReadyToExecute(IActor actor)
{
    if (actor.Existed) return;
    int status = Interlocked.CompareExchange(
        ref actor.Context.m_status,
        ActorContext.EXECUTING,
        ActorContext.WAITING);
    if (status == ActorContext.WAITING)
        ThreadPool.QueueUserWorkItem(this.Execute, actor);
}

訊息投遞與執行迴路

Post 將訊息入佇列後呼叫 ReadyToExecute;Execute 取出訊息呼叫使用者的 Receive,執行完畢後視狀態決定是否重新排程:

void IActor.Execute()
{
    T message;
    lock (this.m_messageQueue) { message = this.m_messageQueue.Dequeue(); }
    this.Receive(message);
}

private void Execute(object o)
{
    IActor actor = (IActor)o;
    actor.Execute();

    if (actor.Existed)
    {
        Thread.VolatileWrite(ref actor.Context.m_status, ActorContext.EXITED);
    }
    else
    {
        Thread.VolatileWrite(ref actor.Context.m_status, ActorContext.WAITING);
        if (actor.MessageCount > 0) this.ReadyToExecute(actor);
    }
}

關鍵在於 VolatileWrite 後再檢查 MessageCount,雖中間可能有新訊息到達觸發並行 ReadyToExecute,但 CAS 機制保證只會有一個成功,邏輯完備。

使用範例:計數器 Actor

public class Counter : Actor
{
    private int m_value;
    public Counter() : this(0) { }
    public Counter(int initial) { this.m_value = initial; }

    protected override void Receive(int message)
    {
        this.m_value += message;
        if (message == -1)
        {
            Console.WriteLine(this.m_value);
            this.Exit();
        }
    }
}

static void Main()
{
    Counter counter = new Counter();
    for (int i = 0; i < 10000; i++) counter.Post(i);
    counter.Post(-1);
    Console.ReadLine();
}

單一 Actor 內無並發,業務邏輯純淨無鎖。完整實作不足 150 行,下一篇將結合 F# 展現更強表達力並進行效能剖析。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved