Monday, 24 September 2012

Actors in C# with NAct

The Actor Model is a popular way to get reliable currency into your application through isolated immutability.

Here we will see how to create a basic Actor and use that Actor to calculate primes just as in the previous Java and C# examples.



private static void Main(string[] args)  
{  
    if(args.Length < 2)  
    {  
        Console.WriteLine("Usage: number numberOfParts");  
        return;  
    }  
    int primesBound = int.Parse(args[0]);  
    int concurrency = int.Parse(args[1]);  
    Stopwatch stopwatch = Stopwatch.StartNew();  
    int count = CountPrimes(primesBound, concurrency);  
    stopwatch.Stop();  
    Console.WriteLine("Found {0} primes under {1}", count, primesBound);  
    Console.WriteLine("It took {0} seconds", (stopwatch.ElapsedMilliseconds)/1.0e3f);  
    Console.ReadKey();  
}  

Here we simply take in the upper bound of the number range in which we want to find primes and the level of concurrency like before in our Java example.

Here we will see how to use the open source library NAct to create Actors in C#.First we must define an actor interface :-
public interface IPrimesActor : IActor  
{  
    Task<int> CountPrimesInRange(int lower, int upper);  
}  

Then we must implement our actor interface :-

public class PrimesActor : IPrimesActor  
{  
    async Task<int> IPrimesActor.CountPrimesInRange(int lower, int upper)  
    {  
        return await Task.Factory.StartNew(() => PrimesComputation.CountPrimesInRange(lower, upper));  
    }  
}  

And finally, you need to tell NAct to turn your object into an actor, as you create it by using the ActorWrapper.
The object you get back from the wrapper is an NAct proxy. Whenever you call a method on it, NAct will call the same method on your object at some point in the right thread.

Here is CountPrimes implemented using NAct Actors.
internal static int CountPrimes(int bound, int concurrency)  
{  
    var tasks = CountPrimesAsync(bound, concurrency);  
    var sums = tasks.GetAwaiter().GetResult();  
    return sums.Sum();  
}  
private async static Task<int[]> CountPrimesAsync(int bound, int concurrency)  
{  
    int chunks = bound / concurrency;  
    var actors = new List<Task<int>>();  
    for (int i = 0; i < concurrency; i++)  
    {  
        int lower = i * chunks;  
        int upper = (i + 1) * chunks;  
        var actor = ActorWrapper.WrapActor<IPrimesActor>(() => new PrimesActor());  
        var task = actor.CountPrimesInRange(lower, upper);  
        actors.Add(task);  
    }  
    var primeCounts = await Task.WhenAll(actors);  
    return primeCounts;  
}  

And here is the result :-
 Found 664579 primes under 10000000  
 It took 3.636 seconds  

Source code here.

You can find out more about NAct here.
You can install NAct using NuGet using this command.

No comments:

Post a Comment