`

一切为了并行:MS Axum语言教程 <四>

阅读更多
数据流网编程

在程序中,代理之间通过发送和接受消息彼此沟通,他们的沟通被程序的逻辑,程序的状态,从其他代理接受的数据等等所驱动。

与这个控制流模型相提并论的是数据流模型,在此程序的执行只为进入数据流网的数据有效性所驱动,数据在网络中移动的时候,计算同时进行着。在Axum语言中,数据流网由网络操作符所创建。一个网络操作符是个二进制表达式,左边的操作数是源,右边的操作数是目的。操作数可以是标量或矢量格式,这里标量是一个单值的数据类型,而矢量可以是数组或者数列。

下面我们根据操作数的类型对网络操作加予区分。

一对一:传递
在前面我们已经看过如何用操作符 ==> 建立管道。该操作有个单一的源交互点,并把结果传递给一个目标交互点。和传递类似的,“-->”为一次性传递操作符,该操作符从源头到目的只传递一次消息,在第一条消息传递完毕之后就断开连接。

除了建立管道,操作符还有其他用处,例如,它可以用以建立一个事件驱动的系统,根据事件采取不同的行动来做出响应。


想想普通的GUI应用中是如何操作诸如鼠标点击,按键之类的时间的,这些时间可以被当成是通道:
channel GUIChannel { 
 // MouseEvent is an enum with values Up and Down 
 input MouseEvent Click; 
 // Key describes which key was pressed 
 input Key KeyPress; 
 // Rect is a rectangle to repaint 
 input Rect Paint; 
}


操作请求的代理GuiHandler可以这么实现:
agent GUIHandler : channel GUIChannel 
{ 
    public GUIHandler() { 
          PrimaryChannel::Click ==> HandleClick;
          PrimaryChannel::KeyPress ==> HandleKeyPress;
          PrimaryChannel::Paint ==> HandlePaint; 
   }
   void HandleClick(MouseEvent mouseEvent) { ... }
   void HandleKeyPress (Key key) { ... } 
   void HandlePaint (Rect rect) { ... }
}

GUIHandler的构造器建立了三个简单的网络,将进入的消息传递给响应的操作方法。

多对一:多元与组合

下面两个操作符有个矢量的源头而只有一个目的。

多元操作符 ">>-" 左边有一列的源头,一旦数据送达任一源头,就会并将数据挨个传递给个单一的目标.

类似的,组合操作符 "&>-" 带有一列源头,挨个接受数据,并将他们打包成一个数组(由此得名“组合”)后讲其送给单一的目的。不同的是,组合会等到所有源头都有消息后才进行打包和发送的工作的.

请看例子:我们有个带有2个交互点的数组,包含数字10和20
var ip1 = new OrderedInteractionPoint<int>(); 
var ip2 = new OrderedInteractionPoint<int>(); 
ip1 <-- 10; 
ip2 <-- 20; 
var ips = new OrderedInteractionPoint<int>[] { ip1, ip2 };

多元表达式如下:
ips >>- PrintOneNumber;

该表达式将数组ips的数据送至由方法PrintOneNumber创建的节点。
void PrintOneNumber(int n) { Console.WriteLine(n); }

相应的,我们建立组合的表达式:
ips &>- PrintManyNumbers;


这个表达式会所有的数字当成一个消息送给一个接受int数组的节点
void PrintManyNumbers(int[] nums) { 
 foreach(var i in nums) 
     Console.WriteLine(i);
 }


当你需要等多个以任意顺序送抵的消息时,组合就很有用。下面的表达式组合了两个交互点ip1和ip2的输出,并把结果送交互点twoNumbers:
receive( { ip1, ip2 } &>- twoNumbers );

上面的表达式用花括号来创建数组。在Axum语言中,建立隐含数组是十分便利的语法结构,经常被用在创建网络表达式.我们在下面会看到如何建立一个更复杂的网络。

一对多:广播与轮流
最后两种网络操作符带有一个单一源交互点,将数据发送给多个目标。

广播操作符“-<<”左边是一个单一的焦点,右边是一系列交互点。它将左边的所有数据发送至右边所有的交互点。

将数据发送给多个目标可以用以实现"发布-订阅”场景,数据从发布者被送抵所有的订阅者。

最后,轮流操作符“ -<:” 将数据从单一源头的数据以循环的顺序发送给右手边的集合。轮流在需要负载平衡的场景就非常有用了。例如我们需要个“worker”池来响应从源头发布过来的数据。

把所有这些知识点串接起来,我们从新考虑一下前面的adder例子,并用数据流网来实现它。

agent AdderAgent : channel Adder { 
  public AdderAgent() { 
   var ipJoin = new OrderedInteractionPoint<int[]>(); 
   { PrimaryChannel::Num1 ==> ShowNumber, PrimaryChannel::Num2 ==> ShowNumber } &>- ipJoin -<: { GetSum, GetSum } >>- PrimaryChannel::Sum; 
   
   } 
 
   private int ShowNumber(int n) { 
        Console.WriteLine("Got number {0}", n); 
        return n; 
  } 
  
  private function int GetSum(int[] nums) { 
       return nums[0] + nums[1];
   }
}



说明如下:网络的第一个节点有个带有2个元素的数组:每个元素传递送至的数据给移交方法ShowNumber。这个方法可以用来调试,以跟踪那么到达输入端口的消息。

之后,数组节点被组合到带有整数数组的中间点ipJoin。这个节点的作用是把两个数字组合成一个序列以便能被方法GetSum处理。

网络的下一个节点仍是一个数组,它带有由方法GetSum所实现的两个转换节点。因为GetSum被声明称函数,它的执行被设置成并发的,以提高网络的流量。

最后GetSum转换后的输出被通过多元操作送至端口Sum。

分布式axum应用

回想上次发表计算梅森数列的例子,从Erlang到PlINQ纷纷上阵,在算法与语言的潜力被挖掘殆尽之后,唯一能大幅度提高性能的方式就是利用分布式。

Axum对分布式应用提供很好的支持。实际上,Axum对于isolation如此的严格使得域与域可以在本地或者远程交互而无须对模型做出修改。By borrowing a page from how the Web is programmed and making it scale to the small, we can easily go back to its roots and 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运行时支持了本地的进程内的通道,同时也支持基于WCF的通道。

要取得域内的代理,你必须赋予它一个地址。本地和远程的场景是类似的。进程内的处理简单些,因为哪怕你不赋予地址,代理的类型名称仍可作为一个默认的地址。在分布式场景,我们得多一些工作。

Axum运行通过IHost接口来处理这一切,它允许你赋予代理一个域内的名字。更准确的说,我们所关联的是所保有的
In the Axum runtime, we have support for local, in-process channels as well as WCF-based channels. To reach an agent within a domain, you have to give it an address; this is true in local and remote scenarios alike. Within a process, it’s a bit easier, because the agent type name itself acts as a “default” address if nothing else, but in the distributed scenario, we have to do a bit more. But it’s just a little bit. The Axum runtime does this through an interface called IHost, which allows you to give the agent an address within a domain. To be precise, what we associate with an address is a factory for agents of the hosted type, which 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 one for WCF and one for in-process communication. The address may be associated with an existing domain instance, in which case created agent instances are associated with that domain, or it may be associated with no domain instance, in which case created agent instances are associated with a new domain instance, one for each new connection. For example, if you are building an Axum-based server, you can host domains as services with the following code:
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics