Jan 31

AXUM PART TWO

Editor’s Note: most of the information provided below comes from the Axum Programmers Guide.. It is my only source of material at the moment, so please follow along with the article and start to imagine the possibilities.

http://msdn.microsoft.com/en-us/devlabs/dd795202

image_thumb3

Just used to M-V-VM for GUI handling ? Now here comes parallel programming. How can you handle something in parallel  asynchronous environment that scales properly and doesn’t block parallel operations ?.

Writing a parallel program requires partitioning the solution into a number of parallel tasks. Some problems are friendly to parallelization because the tasks can run independently of each other. In other problems the tasks have interdependencies and require coordination.

In a gameplay simulation, the game is modeled using parallel but interacting objects. The state and behavior of an object have huge impact on the objects around it.

What is your motivation for writing a game in parallel would be to make it run faster and do more while it executes. ?  Games and interactive applications process user input while performing a background tasks. User responsiveness can be  very important as well, long-latency components such as I/O or user input.can slow even asynchronous operations down. Axum’s goal is to never make you worry about concurrency but how do you program for that. Especially a GUI (Graphic User Interface) ?

Constructing a parallel GUI handler in Axum

In an Axum program agents are communicate with each other by sending and receiving messages, their communication can be driven by the application logic, the state of the program, the data received from the other agents and so on.

Compare  this with control-flow style model with the dataflow model, where execution of the program is driven only by the availability of the data entering the dataflow network, and the computations are performed as the data moves through the network.

In Axum, dataflow networks are built using network operators. A network operator is a binary expression, with a source sub-expression as a left-hand operand and a target expression as a right-hand operand. The operands can be either scalar or vector forms, where by “scalar” we understand a single-valued data type, and by “vector” either an array or an IEnumerable of a type. In this case we will classify  network operators by the type of their operands.

Building a Pipeline

image_thumb9

In part one we learned using end of Application channel is implemented in the Axum runtime. The runtime instantiates the agent implementing channel Microsoft.Axum.Application sends command line parameters to the channel’s CommandLine port, and then waits for a message on port ExitCode. When the message is received, the application shuts down.

The agent Program waits for a message to arrive on its CommandLine port (the receive statement), and then signals completion by sending a message to port ExitCode (operator <--). The agent Program has a built-in property PrimaryChannel to access the channel being implemented – sometime we will also call it “agent’s primary channel”. The double-colon “::” is used to access the channel’s port.

Receiving a message is a blocking operation in Axum – a receive statement  that attempts to read from an empty port will stall  until a message arrives to that port. On the other hand, send is asynchronous – the sender of the message doesn’t wait for it to arrive to the destination.

Axum gives us two distinct approaches to orchestration:

  • control-flow-based 
  •  data-flow-based .

The two are combined for ultimate expressiveness and power.

In Axum, messages are sent to and received from interaction points. An interaction point from which a message originates is called the source, and the destination is called the target.

An interaction point can be both a source and a target, meaning that it can both send and receive messages. This allows composition of multiple interaction points into dataflow networks.

A Dataflow network is a messaging construct that receives data, does something with it (i.e., a transformation). Unlike control-flow logic that is based on conditional statements, loops, and method calls, data-flow networks base their logic on forwarding, filtering, broadcasting, load-balancing, and joining messages that pass through the network. It’s a different and complementary approach to handling messages.

RECAP

Axum supports two communication models:

  • Control-flow driven communication between agents;
  • Dataflow driven communication with networks.

USING THE FORWARD OPERATOR TO HANDLE GUI OPERATIONS

ONE TO ONE EXAMPLE

Forward operator ==> sends each message produced by the source to the target.
Forward once operator --> forwards a single message to the target, then disconnects.

Previously, we learned how to build a pipeline using forward operator ==>. This operator takes a single source interaction point and forwards the result to a target interaction point.

Similar to forward, forward once operator --> forwards a message from the source to the target, but then disconnects after the first message.

Let’s use the forward operator now to build an event-driven system  for a GUI where different actions are performed in response to the events (such as: a mouse click, a key press, and a window paint request). These events can be represented as ports on a channel:

   1:  channel GUIChannel
   2:  {
   3:  // MouseEvent is an enum with values Up and Down
   4:  input MouseEvent Click;
   5:  // Key describes which key was pressed
   6:  input Key KeyPress;
   7:  // Rect is a rectangle to repaint
   8:  input Rect Paint;
   9:  }

 

The handler code would look like this in AXUM

   1:  agent GUIHandler : channel GUIChannel
   2:  {
   3:  public GUIHandler()
   4:  {
   5:  PrimaryChannel::Click ==> HandleClick;
   6:  PrimaryChannel::KeyPress ==> HandleKeyPress;
   7:  PrimaryChannel::Paint ==> HandlePaint;
   8:  }
   9:  void HandleClick(MouseEvent mouseEvent)
  10:  {
  11:  ...
  12:  }
  13:  void HandleKeyPress (Key key)
  14:  {
  15:  ...
  16:  }
  17:  void HandlePaint (Rect rect)
  18:  {
  19:  ...
  20:  }
  21:  }

The constructor sets up three simple networks that forward incoming messages to the corresponding handler methods. There is more than one type of operator available depending on what you are attempting to accomplish.

MANY TO ONE OPERATORS

  • Multiplex operator >>- sends messages from a vector of sources to a single target.  the multiplex operator takes a vector of sources as the left-hand operand and forwards data from each into a single target as soon as it arrives at any of the sources.
  • Combine operator &>- joins multiple messages from sources and propagates them to a target as an array.  Combine waits for all sources to have a message, before joining them together and propagating them all to the target
    • Use Cases: Combine is useful when you need to wait for multiple messages that can arrive in any order.

ONE TO MANY OPERATORS

  • Broadcast operator -<< Broadcast operator -<< copies one message to multiple targets. The operator 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.
    • Use Cases:  Propagating data to multiple sources can be used to implement a publisher-subscriber scenario where data from a publisher is propagated to a number of subscribers.
  • Alternate operator -<: round-robins messages between multiple targets. It propagates the data from the single source to the targets in the right-hand collection in round-robin order.
    • Use Cases:  Alternate is useful in the scenarios where we want to load-balance work. For example, we might want to have a pool of “workers” to handle data coming into the source.

Creating a Distributed Application in Axum

image

In Axum, domains can interact locally or remotely with no change in the model. This takes a lot of the large scale architecture of the web and brings it small scale, allowing us to go back to its interact across networks.

With domains being services of a SOA application, agents the protocol handlers, and schema the payload definitions (b.t.w. schema are XML-schema compliant), we have an easy time mapping Axum to web services. Axum has support for local, in-process channels as well as WCF-based channels.

An agent within a domain, requires you to give it an address; this is true in local and remote scenarios Inside a process, the agent type name itself acts as a “default” address.

Implementing the IHOST Interface

IHost  allows you to give the agent an address within a domain. This is actually a factory for agents of the hosted type. It is used to create agent instances when someone creates a new connection. Each underlying communication / service hosting framework has to have its own implementation of IHost;

Axum comes with two:

  • WCF 
  • in-process communication

The address may be associated with an existing domain instance, or no domain instance.

Hosting a Service in Axum

Here’s an example from the documentation on how to host an AXUM service.

   1:  channel Simple 
   2:  {
   3:    input string Msg1; output string Msg2;
   4:   }
   5:   
   6:  domain ServiceDomain 
   7:   
   8:  { agent ServiceAgent : channel Simple 
   9:     { 
  10:       public ServiceAgent ()  { // Do something useful. }
  11:      }
  12:   }
  13:   
  14:  agent Server : channel Microsoft.Axum.Application 
  15:  { 
  16:          public Server () 
  17:          {       
  18:             var hst = new WcfServiceHost(new NetTcpBinding
  19:               (SecurityMode.None, false)); hst.Host<ServiceDomain.ServiceAgent>
  20:               ("net.tcp://localhost/Service1");
  21:             }  
  22:  }
  23:   

 

Each time some client connects to the address "net.tcp://localhost/Service1,” a new instance of ServiceAgent will be created, associated with a brand new ServiceDomain instance.

If instead, we wanted created agents to be associated with a single domain instance, we have to pass one in to ‘Host’

   1:  hst.Host<ServiceDomain.ServiceAgent("net.tcp:...", new ServiceDomain());


CLIENT ACCESS

The Client-Side provider is called ICommunicationProvider.

Connecting to a “new” communication service would look like this:

   1:  var prov = new WcfCommunicationProvider
   2:  (new NetTcpBinding(SecurityMode.None, false)); 
   3:  var chan = prov.Connect<Simple>("net.tcp://localhost/Service1");

It is not always necessary to create a new communication provider for each connection, or a new host for each Host call.

BLOCKERS

Unfortunately with AXUM and .NET there are a few limitations to writing “async” code..

  • use of .NET synchronization primitives such as Monitor.Enter.
  • synchronous I/O, e.g. Console.ReadLine.
  • receive expressions
  • receive statement

Axum, uses messages and empty/full variables for all data-exchange synchronization needs. Synchronization for protection purposes are handled declaratively.

The rule of thumb around declaring asynchronous methods is as follows:

  • Any method containing a receive expression or statement should be asynchronous.
  • Any method calling an API that is known to have an APM variant should be asynchronous.
  • Any method calling an asynchronous method should be asynchronous.

For More information see:

Axum and Game Development
Axum and Visual Studio 2010 Shell
Stopping A Pipeline During Calculation?
Axum Presentation at the Iowa Code Camp