Programmerare, skeptiker, sekulärhumanist, antirasist.
Författare till bok om C64 och senbliven lantis.
Röstar pirat.
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
Tags: Akka .NET
Bjud mig på en kopp kaffe (20:-) som tack för bra innehåll!
Leave a Reply