簡體   English   中英

擴展 Akka.Net

[英]Scaling Akka.Net

我們將 Akka.net 框架用於能源領域的高度擴展應用程序。

我們將 Akka.net 用於各種任務,主要采用以下形式:

var system=ActorSystem.Create("actorSystem");
var props=Props.Create<UpdateActor>();
               .WithRouter(new SmallesMailboxPool(100));
var actorRef=system.ActorOf(props,"UpdateActor");
foreach(var timerow in timeRowList)
   actorRef.Tell(timerow)

不幸的是,Akka.net 框架在許多情況下擴展性非常差。 CPU 負載僅為 12%。 顯然只使用了一個線程或幾個線程。

如何配置 Akka.Net 以使用多個線程來處理參與者?

這是一個有根據的猜測,但如果您使用的是SmallestMailboxPool ,請記住它在非阻塞 I/O 中的工作非常糟糕,並且在存儲時非常糟糕。

首先通常是檢查是否有阻塞操作(如同步 I/O,調用AsyncMethod().ResultThread.Sleep ),這將阻塞當前線程,有效防止它被其他actor 使用。

另一個問題是針對最小郵箱路由器的,它與存儲和持久參與者有關。

藏匿

存儲是處理多步驟操作的流行方法之一。 這種模式可以表示如下。

  public class MyActor : ActorBase, IWithUnboundedStash
  {
     public IStash Stash { get; set; }

     public Receive Active(State workUnit) => message =>
     {
        switch(message)
        {
           case DoWork: 
              // stash all messages not related to current work
              Stash.Stash(message); 
              return true;
           case WorkDone done:
              // when current unit of work is done, unstash pending messages
              Stash.UnstashAll();
              Become(Idle);
              return true;
        }
     };

     public bool Idle(object message)
     {
        switch(message)
        {
           case DoWork work: 
              StartWork(work.State);
              Become(Active(work.State)); //continue work in new behavior
              return true;
           default: 
              return false;
        }
     } 

     public bool Receive(object message) => Idle(message);
  }

這種情況很常見,即持久參與者在恢復過程中使用它。 問題是,它正在清理郵箱,這讓SmallestMailbox路由器誤以為這個參與者的郵箱是空的,而實際上它只是隱藏所有傳入的消息。

這也是為什么不應該使用SmallestMailbox路由器路由持久 actor的原因! 天。 我想不出任何將持久角色放在任何類型的路由器后面都是有效選擇的場景。

我認為您需要做的是創建一個演員協調器類,並在內部創建一個演員列表/字典。 然后(據我所知)在您將新更新告訴協調員后,他們應該並行工作。

public class UpdateCoordinator : ReceiveActor
{
    //all your update referenced
    private readonly Dictionary<int, IActorRef> _updates;

    public UpdateCoordinator()
    {
        _updates = new Dictionary<int, IActorRef>();

        //create the update reference
        Receive<UpdateMessage>(updateMessage =>
        {
            //add to the list of actors
            CreateUpdateReferenceIfNotExists(updateMessage.Identifier);

            IActorRef childUpdateRef = _updates[updateMessage.Identifier];

            //start your update actor
            childUpdateRef.Tell(updateMessage);
        });
    }

    private void CreateUpdateReferenceIfNotExists(int identifier)
    {
        if (!_updates.ContainsKey(identifier))
        {
            IActorRef newChildUpdateRef = Context.ActorOf(Props.Create(()=> new UpdateActor(identifier)), $"Update_{identifier}");
            _updates.Add(identifier, newChildUpdateRef);
        }
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM