2016-03-24 13 views
2

akka.net ile çalışan bir kavram kanıtı almaya çalışıyorum. Eminim çok yanlış bir şey yapıyorum, ama ne olduğunu anlayamıyorum.Benim Akka.Net Demo inanılmaz derecede yavaş

Oyuncularımın düğümleri oluşturmasını istiyorum. Daha sonra bu iş objelerden karmaşık bir grafik olacak, ama şimdilik böyle basit bir doğrusal yapıya denemek istiyorum:

enter image description here

Ben 9 adım uzaklıktadır Komşuma bir düğüm sormak istiyorum. Bunu yinelemeli bir şekilde uygulamaya çalışıyorum. 9 adım uzaklıktaki bir komşu için 9 no'lu düğüme gidiyorum, sonra 8 adım ötedeki bir komşu için 8 no'lu node'a sorarım. Son olarak, bu cevap # 0 değerini bir cevap olarak döndürmelidir.

Kodum işe yarıyor, ancak yürütmek için 4 saniye'dan daha uzun sürüyor. Neden?

Bu benim tam kod listesidir:

using System; 
using System.Collections.Generic; 
using System.Diagnostics; 
using System.Linq; 
using Akka; 
using Akka.Actor; 

namespace AkkaTest 
{ 
    class Program 
    { 
     public static Stopwatch stopwatch = new Stopwatch(); 
     static void Main(string[] args) 
     { 
      var system = ActorSystem.Create("MySystem"); 

      IActorRef[] current = new IActorRef[0]; 

      Console.WriteLine("Initializing actors..."); 

      for (int i = 0; i < 10; i++) 
      { 
       var current1 = current; 
       var props = Props.Create<Obj>(() => new Obj(current1, Guid.NewGuid())); 
       var actorRef = system.ActorOf(props, i.ToString()); 
       current = new[] { actorRef }; 
      } 
      Console.WriteLine("actors initialized."); 

      FindNeighboursRequest r = new FindNeighboursRequest(9); 

      stopwatch.Start(); 

      var response = current[0].Ask(r); 
      FindNeighboursResponse result = (FindNeighboursResponse)response.Result; 
      stopwatch.Stop(); 
      foreach (var d in result.FoundNeighbours) 
      { 
       Console.WriteLine(d); 
      } 

      Console.WriteLine("Search took " + stopwatch.ElapsedMilliseconds + "ms."); 
      Console.ReadLine(); 
     } 
    } 
    public class FindNeighboursRequest 
    { 
     public FindNeighboursRequest(int distance) 
     { 
      this.Distance = distance; 
     } 
     public int Distance { get; private set; } 
    } 

    public class FindNeighboursResponse 
    { 
     private IActorRef[] foundNeighbours; 

     public FindNeighboursResponse(IEnumerable<IActorRef> descendants) 
     { 
      this.foundNeighbours = descendants.ToArray(); 
     } 

     public IActorRef[] FoundNeighbours 
     { 
      get { return this.foundNeighbours; } 
     } 
    } 


    public class Obj : ReceiveActor 
    { 
     private Guid objGuid; 
     readonly List<IActorRef> neighbours = new List<IActorRef>(); 
     public Obj(IEnumerable<IActorRef> otherObjs, Guid objGuid) 
     { 
      this.neighbours.AddRange(otherObjs); 
      this.objGuid = objGuid; 
      Receive<FindNeighboursRequest>(r => handleFindNeighbourRequest(r)); 
     } 

     public Obj() 
     { 
     } 

     private async void handleFindNeighbourRequest (FindNeighboursRequest r) 
     { 
      if (r.Distance == 0) 
      { 
       FindNeighboursResponse response = new FindNeighboursResponse(new IActorRef[] { Self }); 
       Sender.Tell(response, Self); 
       return; 
      } 

      List<FindNeighboursResponse> responses = new List<FindNeighboursResponse>(); 

      foreach (var actorRef in neighbours) 
      { 
       FindNeighboursRequest req = new FindNeighboursRequest(r.Distance - 1); 
       var response2 = actorRef.Ask(req); 
       responses.Add((FindNeighboursResponse)response2.Result); 
      } 

      FindNeighboursResponse response3 = new FindNeighboursResponse(responses.SelectMany(rx => rx.FoundNeighbours)); 
      Sender.Tell(response3, Self); 
     } 
    } 
} 
+0

ActorSystem'i oluşturduktan sonra kronometreyi başlatıp yeniden deneyebilir misiniz? –

+0

Tam olarak bu kodun yaptığı şeydir - ya da en azından neyi amaçladığım. Kronometreyi _after_ 'for (int i = 0; i <10; i ++)' döngüsünü başlatıyorum. – user1691896

+0

Oh evet yanlış okumuş. Horusiath'ın dediği gibi, aktörler engellememeli, bir açlık açlığı yaşıyorsunuz demektir. –

cevap

4

böyle yavaş davranışın nedeni sor kullanmak yoludur (kullanmadan bir olmadı, ama bu daha sonra ele alacağız). Örneğinizde, her bir komşuyu bir döngüde soruyorsunuz ve ardından geçerli aktörü aktif olarak engelleyen response2.Result'u hemen yürütün (ve üzerinde bulunduğu parçacığı). Yani aslında engelleme ile senkronize akış yapıyorsunuz.

Bunu düzeltmenin en kolay yolu, Ask'dan döndürülen tüm görevleri toplamak ve hepsini toplamak için bir döngü içinde beklemeden Task.WhenAll'u kullanmaktır. Bu örneği almak için: Bu bir daha hızlıdır.

NOT: Bir aktörün içine sor kullanmamalısınız Genel olarak: Ask kullanılarak genel olarak bu yüzden her cari aktör içindeki bir dinleyici ayırdığından sormak

  1. ile mesaj taşıyorum daha ÇOK ağırdır Tell.
  2. İleti zincirleri aracılığıyla ileti gönderirken, istek ücreti ek olarak her bir oyuncu aracılığıyla iletiyi iki kez (istek için ve yanıt için bir tane) aktarır. Popüler desenlerden biri, A ⇒ C ⇒ C ⇒ D'den istek gönderirken ve D'den tekrar A'ya yanıt verdiğinizde, iletinin tüm zincir geri geçirilmesi gerekmeden doğrudan D ⇒ A'ya yanıt verebilirsiniz. Genellikle Forward/Tell kombinasyonu daha iyi çalışır.
  3. Genelde, gerekli olmadığında Alıcının eşzamansız sürümünü kullanmayın - şu anda, eşitleme sürümüyle karşılaştırıldığında bir oyuncu için daha yavaştır.
+0

Harika cevap, Horusiath. Uygulamamı A⇒B⇒C⇒D paternine ve sonra da doğrudan D'den A'ya değiştirmeye çalışacağım. Bu yaklaşımla ilgili bir sorunum var, ancak aktör A tüm cevapları geri aldığını nasıl biliyor? – user1691896

+0

Gerekli tüm düğümlerin geçiş yapıldığından emin olmak için, düğümler kümesini ve derinliklerini izlemeniz ve yanıt verdikten sonra bunları bu setten kaldırmanız gerekir. Diğer gereksinimlerle (yani yalnızca X düğümlerine kadar), İleriye/Geri dönme yaklaşımının daha uygulanabilir olması ancak ek sınırlama olmaksızın, Buraya sor seçeneğinin kullanılmasının haklı olduğu görülmektedir. – Horusiath