Startsidan  ▸  Texter  ▸  Teknikblogg

Anders Hesselbom

Programmerare, skeptiker, sekulärhumanist, antirasist.
Författare till bok om C64 och senbliven lantis.
Röstar pirat.

Enkel trådning i .NET med Akka

2015-04-24

Historiskt sett har det varit ganska komplicerat att bygga multitrådade applikationer i .NET. Rent tekniskt var det enkelt att sjösätta en tråd med hjälp av klassen System.Threading.Thread, men om mycket skulle göras började koden ganska snabbt likna spaghetti. För att minska ner koden kan man använda multitrådade delegater istället för objekt av typen Thread, men det löste inte problemet med spaghettikod. Nyckelorden asynk och await löste både komplexiteten med hopp och returvärde, men var ganska hårt knutet till modellen TAP.

Om jag väljer att jobba med Akka .NET blir trådningen ännu mer hanterad, fast kring en mycket friare modell än TAP, nämligen Actor Model. (I alla nedanstående exempel jobbar jag i Visual Studio 2013.) Tänk dig att jobbar i Windows Forms och att du vill utföra något som kräver ungefär fem sekunders arbete och sedan visar ett meddelande när arbetet är utfört. Min erfarenhet är att Akka .NET fortfarande kan utsättas för förändringar i sitt publika API, så den exakta kodens utseende kan variera – jag kör Akka 1.0.0. För att visa detta skapar jag ett helt nytt Windows Forms-projekt (C# med .NET Framework 4.5.1) och installerar Akka .NET från Package Manager Console genom att skriva:

Install-Package Akka

Om du inte ser Package Manager Console, Klicka Tools, NuGet Package Manager och Package Manager Console.

Akka .NET använder meddelanden för att kommunicera. Meddelanden är kort och gott godtyckliga objekt som initieras och skickas i samband med att ett asynkront anrop görs. Meddelandet bör vara immutable, alltså meddelandet ska inte kunna modifieras, vilket kan implementeras genom att objektets data inte har några publika setters.

class AkkaMessage
{
   public string MyValue { get; private set; }

   public AkkaMessage(string myValue)
   {
      this.MyValue = myValue;
   }
}

En actor (aktör) är den t.ex. det objekt som kan ta emot ett meddelande och agera på det. Det som utmärker en sådan aktör är basklassen Akka.Actor.ReceiveActor samt konstruktorn som tar emot meddelandet som skickas till den. För att ta emot meddelandet används den generiska metoden Receive vars argument är det som ska göras med meddelandet. Den generiska metodens typparameter är meddelandeklassen. Så i följande kod anropar vi Receive och skickar med kod jobbar i fem sekunder för att sedan visa en meddelanderuta.

class AkkaActor : Akka.Actor.ReceiveActor
{
   public AkkaActor()
   {
      this.Receive(x =>
         {
            System.Threading.Thread.Sleep(5000);
            System.Windows.Forms.MessageBox.Show(x.MyValue);
         }
      );
   }
}

Nu återstår bara initieringen och själva anropet. Följande kod har jag skrivit i mitt programs huvudformulär. Först har jag ett privat fält av typen Akka.Actor.ActorSystem som representerar motorn i Akka – det s.k. actorsystemet. I Load-eventet för formuläret initierar jag systemet med funktionen Create. Create vill ha ett namn på systemet i sin kostruktor. Slutligen, under Click-eventet på en knapp på formuläret så gör jag anropet som ska hanteras av aktören ovan.

Den första raden anropar funktionen ActorOf för att erhålla en referens till en aktör. Den andra raden utför utför anropet med hjälp av funktionen Tell, och låter ett meddelande skickas med som argument. Meddelandet måste vara av typen AkkaMessage, eftersom jag hårdkodade aktören att hantera den typen.

public partial class Form1 : Form
{
   private Akka.Actor.ActorSystem actorSystem;

   public Form1()
   {
      InitializeComponent();
   }

   private void Form1_Load(object sender, EventArgs e)
   {
      this.actorSystem =
         Akka.Actor.ActorSystem.Create("ActorSystem");
   }

   private void button1_Click(object sender, EventArgs e)
   {
      var m = this.actorSystem.ActorOf(new
         Akka.Actor.Props(typeof(AkkaActor)));
      m.Tell(new AkkaMessage("Hello!"), m);
   }
}

När du kör programmet, notera att programmets fönster är svarsbenäget under den tid programmet pausar pausar (anropet på Sleep), vilket säger oss att aktören och formuläret körs på olika trådar.

Om du istället hade velat implementera detta i Visual Basic, skulle ditt meddelande kunna se ut så här:

Public Class AkkaMessage
   Public Property MyValue() As String
   Public Sub New(MyValue As String)
      Me.MyValue = MyValue
   End Sub
End Class

Aktören skulle kunna se ut så här:

Public Class AkkaActor
   Inherits Akka.Actor.ReceiveActor

   Public Sub New()
      Me.Receive(Of AkkaMessage)(AddressOf MyMessageHandler)
   End Sub

   Private Sub MyMessageHandler(X As AkkaMessage)
      System.Threading.Thread.Sleep(5000)
      MessageBox.Show(X.MyValue)
   End Sub

End Class

Och slutligen, formuläret skulle kunna se ut så här:

Public Class Form1

   Private ActorSystem As Akka.Actor.ActorSystem

   Private Sub Form1_Load(sender As Object, _
      e As EventArgs) Handles MyBase.Load
      Me.ActorSystem = Akka.Actor.ActorSystem.Create("ActorSystem")
   End Sub

   Private Sub Button1_Click(sender As Object, _
      e As EventArgs) Handles Button1.Click
      Dim M = Me.ActorSystem.ActorOf( _
         New Akka.Actor.Props(GetType(AkkaActor)))
      M.Tell(New AkkaMessage("Hello!"), M)
   End Sub

End Class

Categories: C#, VB.NET

Tags: Akka .NET

Leave a Reply

Your email address will not be published. Required fields are marked *



En kopp kaffe!

Bjud mig på en kopp kaffe (20:-) som tack för bra innehåll!

Bjud på en kopp kaffe!

Om...

Kontaktuppgifter, med mera, finns här.

Följ mig

Twitter Instagram
GitHub RSS

Public Service

Folkbildning om public service.

Hem   |   linktr.ee/hesselbom   |   winsoft.se   |   80tal.se   |   Filmtips