July 05, 2009

Parallel programming with Axum

This week I get chance to look further in Axum 2.0 – MS DevLab’s .NET language for building parallel applications. The 2.0, which is launched last week has some bug fixing & additional features for asyc programming as compare to last version. However 2.0 is yet incubation technology designed to make parallel applications safer, scalable & easier to write.

One of the goals of Axum is to let you program without worrying about concurrency – your program becomes fast and responsive by default, not as a result of an afterthought or a retrofit.

The Axum is builds upon 4 principles:

  • isolation,
  • agents,
  • message-passing and
  • data flow

Note that Axum programming is somewhat different than normal C# program. The following C# elements are not present in Axum

  • Classes, interfaces and structs
  • Operator declarations
  • Properties
  • Const fields and const locals
  • Static fields and methods

Axum is different from object oriented programming – first unlike objects, agents do not provide public methods or exhibit their state, you can’t modify fields & you cannot call a method on an agent and wait for it complete. Instead, you can send it a message, and arrange for the agent to “get back to you” with a response.

Axum can be grouped into the following main categories

  • Agents and domains - similar to class, types presenting a collection of ports, interacts with each other via message-passing over separately defined channels, each agent must implement a single channel type. Domain – Every Axum program consists of at least one domain, agents can be nested within domain
using System;
using Microsoft.Axum;
using System.Concurrency.Messaging;

namespace Axum
{
public domain Program
{
agent MainAgent : channel Microsoft.Axum.Application
{
public MainAgent()
{
String [] args = receive(PrimaryChannel::CommandLine);

// TODO: Add work of the agent here.

PrimaryChannel::Done <-- Signal.Value;
}
}
}
}
  • Channels – defines protocols, ports (input/output) through which data passes, compatible with WCF channels,

var chan = new channelTest("TestService"); // channelTest declared somewhere else

  • Schema - defines the structure and rules for data passed between isolated components, i.e. agents
  • Interleaved control flow

  • Networks - combinations of interaction points into more complex message routes, formed using seven binary operators and one unary operator:
  1. Forward (==>), link its left operand to its right operand so that the left operand will attempt to propagate data sent to it to the right operand. The link exists until the expression is disposed or explicitly disconnected.


  2. Forward once (-->), links its operands in the same manner and is similarly disposed, but which automatically disconnects as soon as one message is successfully propagated from the left to the right operand. Note the similarity to the operator ‘<--‘, which represents an originating send operation.


  3. Multiplex (>>-), links a collection of left-hand operands to a single right-hand operand in the same manner as ‘forward.’ All connections are established at once and disconnected together.


  4. Combine (&>-) , i.e. ‘Join’, which accepts a collection of interaction points as its left-hand operand and produces an array of data, one value from each interaction points per message. Also, for a left-hand operand that is a tuple of interaction points, the expression will produce a tuple of values.


  5. Broadcast (-<<), accepts a single interaction point on the left and a collection of interaction points on the right; it propagates all data from the left operand to all the interaction points on the right.


  6. Alternate (-<:), propagates data from the single left operand to the interaction points in the right-hand collection in round-robin order.


  7. Tuple8(,,,), forms a network with the left-hand operand as the visible target and the right-hand operand as the visible source. The two are not linked together: the left operand does not have to also be a source, and the right operand does not have to be a target. (Not yet implemented in compiler)


  8. Filter (???), a unary operator which will create a buffer propagating data that passes the ‘a -> bool’ filter function that is the operand of the filter. (Not yet implemented in compiler)

Following code demonstrates how to achieve parallelism using Axum. In first step we have declared channel which declares parameters through which data passes. The code is similar in the presentation given by Josh Phillips.

using System;
using Microsoft.Axum;
using System.Concurrency.Messaging;

namespace Axum
{
public domain Program
{
// Step 1 - declare channels through which data passes
channel MathOperators
{
input int X;
input int Y;
output int result;
}


In second step we have created agents for adding & multiplying data. These agents run in parallel w/o affecting concurrency etc.

// Step 2 - declare agent 1 (implicit parallelism 1)

private agent AddAgent : channel MathOperators

{
public AddAgent()
{
while (true)
{
result <-- (receive(X) + receive (Y));
}
}
}

// Step 2 - declare agent 2 (implicit parallelism 2)

private agent MultiplyAgent : channel MathOperators
{
public MultiplyAgent()
{
while (true)
{
result <-- (receive(X) * receive (Y));
}
}
}

In last step we input data & performs operations using agents as shown:

// Step 3 - main agent
private agent MainAgent : channel Application
{
public MainAgent()
{
var adder = AddAgent.CreateInNewDomain();
var multiplier = MultiplyAgent.CreateInNewDomain();

while (true)
{
Console.Write ("Enter X:");
var x = Int32.Parse(Console.ReadLine());
Console.Write ("Enter Y:");
var y = Int32.Parse(Console.ReadLine());

adder::X <-- x;
adder::Y <-- y;
multiplier::X <-- x;
multiplier::Y <-- y;

Console.WriteLine("Sum: " + receive (adder::result));
Console.WriteLine("Multiplication: " + receive (multiplier::result));
}
}
}
}
}

The output of program is shown below:

axumOut