COmega---ActiveObjects研究笔记
Active Objects
Tutorial
One common pattern of asynchronous programming is that of active objects, or actors. Active objects communicate by asynchronous messages that are processed sequentially by a thread of control that is specific to that object. One way of programming active objects in Cω is by inheritance from an abstract base class:
active objects是一个公共的异步模式编程模式。Active objects间的通信是通过异步的消息机制来实现的,它使用了控制线程对消息进行连续地处理。在Cω中ActiveObject的处理如下:
//创建一个抽象类ActiveObject
public abstract class ActiveObject
{
protected bool done = false; //用于标识是否处理消息
async Start();//定义异步函数
protected abstract void ProcessMessage();//定义抽象的消息处理函数
public ActiveObject()
{
Start();
}
when Start()
{
while (!done) ProcessMessage();
}
}
When an instance of ActiveObject
is created, the Start()
method is called, which spawns a new thread which repeatedly calls the abstract synchronous method ProcessMessage()
. Subclasses of ActiveObject
then override ProcessMessage()
, joining it in a sequence of chords with each of the asynchronous messages that they wish to process.
当Activeobject的实例创建后,Start()方法就会被调用,这里会产生一个新的线程对ProceMessage()方法进行不断地同步进行处理。ActiveObject的子类们重新实现了ProcessMassage()函数后,加入的新消息会基于对象内部同步,对象间的消息却是不同步的。
//定义公共的消息接收器的接口
public interface EventSink { async Post(string message); }
//Distributor是消息的分发类,它继承于ActiveObject与消息接收器的接口EventSink public class Distributor : ActiveObject, EventSink {
//创建用于存入订阅者列表的容器
private ArrayList subscribers = new ArrayList();
//对象的名称 private string myname;
//定义两个异步函数的Subscribe与Post public async Subscribe(EventSink sink); public async Post(string message);
//重新实现消息处理函数 protected override void ProcessMessage()
//需要向订阅者发送的消息加入到subscribers中 & Subscribe(EventSink sink) { subscribers.Add(sink); }
//信息的发送,这里会将subscribers中的所有数据发送到指定的位置 & Post(string message) { foreach (EventSink sink in subscribers) { sink.Post(myname + ":" + message); } }
public Distributor(string name) { myname = name; } }
A Distributor
object can receive asynchronous Subscribe
and Post
messages. Each Post
message is resent to each of the current subscribers. No locking is required for access to the current subscriber list since, although messages can arrive at any time, they are processed strictly sequentially by the Distributor
's message-loop thread (without blocking their sender, of course).
Distributor对象能够接收到异步的订阅者然后向它发送消息。每一次发送消息,都会发给当前所有的订阅者,这里并不需要锁来控制同步,ActiveObject能够向每一个订阅者本身按顺序发送消息,但对于订阅者来说,谁先收到消息则是不一定的。
Since threads are a relatively expensive resource on the CLR, having many instances of this ActiveObject
class around at once will be inefficient. However, ActiveObject-
s are not built in to Cω - they're just one example of the sort of thing one can build easily with the Cω concurrency constructs. Implementing variants of this pattern, such as families of objects that share a custom threadpool implementation is also straightforward.
需要注意的是,在CLR中的线程资源是比较昂贵的,大量的ActiveObject对象将是低效的,尽管如此,ActiveObject,如果要实现高效的操作的话,需要使用自定义的线程,这里的代码只是一个简单的例子。
Example
The following uses active objects to implement a simple publish-subscribe system:
using System; using System.Threading; public abstract class ActiveObject { protected bool done = false; async Start(); protected abstract void ProcessMessage(); public ActiveObject() { Start(); } when Start() { while (!done) ProcessMessage(); } } public interface EventSink { async Post(string message); } public class Distributor : ActiveObject, EventSink { private EventSink{} subscribers = {}; private string name; public async Subscribe(EventSink sink); public async Post(string message); protected override void ProcessMessage() & Subscribe(EventSink sink) { subscribers.Add(sink); } & Post(string message) { foreach (sink in subscribers) { sink.Post(String.Format("{0} : {1}",name,message)); } } public Distributor(string name) { this.name = name; } } public class Subscriber: EventSink { private string name; public async Post(string message); public Subscriber(string name) { this.name = name; } when Post(string message) { Console.WriteLine("{0} got message {1}", name, message); } } public class Demo { public static void Main(){ Distributor d = new Distributor("D"); Subscriber a = new Subscriber("a"); d.Subscribe(a); d.Post("First message"); Subscriber b = new Subscriber("b"); d.Subscribe(b); d.Post ("Second message"); Subscriber c = new Subscriber("c"); d.Subscribe(c); d.Post("Third message"); } }
Output
After the output has stopped changing, simply close the console window where ActiveObjects.exe is running such as by using the keyboard shortcut (Alt + Space + C) or the mouse to click on the 'X' in the top right corner of the window.
b got message D : First message c got message D : First message a got message D : First message c got message D : Third message b got message D : Third message a got message D : Second message b got message D : Second message a got message D : Third message c got message D : Second message