ACE相关的Proactor Pattern

简介

前摄器模式是一个异步事件处理模式。这个模式从多个线程分派多个事件到对应的事件处理器重。它允许应用程序不需要对应数量的线程就可以同时执行多个操作。除此之外,它还在对象或者一个分层架构之间创建了一种“松耦合”和“高内聚”。

详细信息

详细信息可以翻阅这本书:《Pattern-Oriented Software Architecture (Volume 2).》

背景

前些时候,我用C++(STL)实现了前摄器模式,并且在想是否我可以用C#和.NET实现这个模式。因为.NET框架已经提供了一些列功能,因此花费的时间比预想的要少。

所需技能

我确信每个程序员都能理解这个模式。
然而,如果有一系列的编程和设计技巧会更容易理解和使用这种事件处理模式。这是让更容易理解所需的一些技能:
你应该知道一点:

  • 信号量
  • 单例模式(看GoF的书)
  • 多线程访问锁定的共享数据
  • 桥接模式(GoF)
  • 线程
  • 如何实现一个对象间的松耦合和高内聚的关系
  • UML
    别被我吓倒。这是有道理的,我想。。。
    什么时候使用这个模式?
    使用这个模式的时机如下:
  • 你想有一个异步事件处理
  • 你的对象应该独立地传送事件
  • 你的事件应该按不同的优先级别被投递
  • 你想在层次或对象间实现松耦合和高聚合

UML类图

Main.jpg
这是一个前摄器模式的类图。
这个例子的想法是让Bird分(当然是在软件中)。Bird将会接受一个FlyEvent从另一只Bird,我们称之为“fly away”方法。

Dispatcher:这个分配器(Dispatcher)将收到的事件分派给Dispatchable。
Dispatchable:一个Dispatchable对象能够接收来自Dispatcher的事件。
PriorityQueue:这个队列中包含已排好队的事件(按不同优先级队列排序)
Registry:包含已注册的Dispatchable对象。
Dispatchable:Dispatchable对象的接口
Bird:接收来自dispatcher的异步消息的Dispatchable对象。

时序图

下面是时序图:
Registering

Register.jpg

Enqueue event

这里写图片描述

Dispatch Event

这里写图片描述

使用前摄器

在使用前摄器模式之前有一些步骤必须完成。
1.每个能接收事件的对象必须实现一个Dispatchable对象并且要从IDispatchable派生。

public class Bird : IDispatchable
{
    /// <summary>
    /// The dispatchable of the bird.
    /// </summary>
    private Dispatchable _dispatchable = new Dispatchable();

1.为什么不直接从Dispatchable对象派生呢?

  • 原因1:这会造成我们不想要的高耦合和低内聚
  • 原因2:数据封装

    2.你应当现在实现在IDispatchable接口中提供的方法。

/// <summary>
/// The handle event of the dispatchable
/// </summary>
/// <param name="ievent">the event to handle</param>
public void HandleEvent(IEvent ievent)
{
    Debug.Assert(ievent != null);

    if (ievent is FlyEvent)
    {

3.在disapatcher(Bird在器构造函数中完成这一步)上注册登记IDispatchable。

/// <summary>
/// Constructor
/// </summary>
public Bird()
{
     // this will register the Bird
      Dispatcher.GetInstance.Register(this);
}

Dispatcher做了什么?
前摄器模式的核心就是Dispatcher。Dispatcher分派排好队的事件给注册过的Dispatchables在每个(单独)线程中。

/// <summary>
/// Dispatches the events to the dispatchable items
/// </summary>
private void Dispatch()
{
      // thread must be running.
      while (_dispachThread.ThreadState == System.Threading.ThreadState.Running)
      {
            // wait for signal
          _autoResetEvent.WaitOne();    

          // the queue should have at least one queue item available
          if( _queue.Count >= 1 )
          {
//The Dispatcher is a Singleton.

/// <summary>
/// This method will return the Dispatchers instance
/// This is a Singleton pattern.
/// </summary>
public static Dispatcher GetInstance
{
   get
   {
        lock (_instanceLock)
        {
            // if the instance exists, then return the
            // already created disptacher
            if (_instance == null)
            {
                  // first time for the singleton
                _instance = new Dispatcher();
            }
            return _instance;
        }
    }
}

记住拥有更高优先级的事件将会优先分派。小心不要产生“饿死”情况。
4.获取Dispatcher的实例。
5.创建一个事件并将其排队放入Dispatcher。决定这个事件的优先级别去排队。

// event fired to the eagle
FlyEvent fly = new FlyEvent();
Dispatcher.GetInstance.Enqueue(_eagle.DISPATCHABLE_ID, 
           fly, Dispatcher.Priority.Normal );

不要做

1.不要在Dispatcher的HandleEvent里处理太多
2.对英雄而言,不要过早的悲观?

待续

前摄器模式可以和多种模式一起被拓展。我会在写这个模式的part2之前等待回应。

原文出处:http://www.codeproject.com/Articles/33011/Proactor-Pattern
Proactor Pattern is an asynchronous event handling pattern.

Introduction
The Proactor Pattern is an asynchronous event handling pattern. This pattern dispatches multiple events from multiple threads to the corresponding event handlers. This allows the application to have multiple operations running simultaneously without requiring the application to have a corresponding number of threads. Besides, it creates a “low coupling” and “high cohesion” between objects or a layered architecture.

Detailed information
Detailed information can be found in this book: Pattern-Oriented Software Architecture (Volume 2).

Background
Some time ago, I implemented the Proactor pattern in C++ (STL), and wondered if I could make this pattern in C# and .NET. Since the .NET framework already provides a set of functionality, it became less time consuming than expected.

Required skills
I’m sure (almost) every programmer could understand this pattern.

However, a set of programming and design skills are required which makes it easier to understand and to use this event handling pattern. Here is the set of skills which makes it easier to understand:

You should know a bit about:

Semaphores
Singleton Pattern (see the GoF book)
Locking shared data which can be accessed from multiple threads
Bridge Pattern (GoF)
Threads
How to realize a “low coupling” and “high cohesion” relationship between objects
UML
Don’t get daunted by me. It’s reasonable, I think…

When to use this pattern?
Use this pattern if:

you like to have an asynchronous event handling
your objects should independently transport events
your events should be delivered with different priority levels
you like to realize “low coupling” and “high cohesion” between layers or objects

UML class diagram

This is the class diagram of the Proactor pattern.

The idea of this example is to let the Bird fly (in software, of course). The Bird will receive a FlyEvent from another Bird and will call its “fly away” method.

Main.jpg

Dispatcher: the dispatcher dispatches the received events to the Dispatchables.
Dispatchable: a Dispatchable object could receive events from the dispatcher.
PriorityQueue: this queue contains the enqueued events (ordered in separate priority queues).
Registry: contains the registered Dispatchable objects.
IDipatchable: the interface to the Dispatchable objects.
Bird: the Dispatchable object which will receive asynchronous events from the dispatcher.

Sequence diagrams

Here are the sequence diagrams:

Registering

Register.jpg

Enqueue event

这里写图片描述

Dispatch Event

这里写图片描述

Using the Proactor

Here is a set of instructions which must be done before using the Proactor Pattern.

Every object which can receive an event must implement a Dispatchable object and inherit from the IDispatchable.
Hide Copy Code
public class Bird : IDispatchable
{
///
/// The dispatchable of the bird.
///
private Dispatchable _dispatchable = new Dispatchable();
Why not inherit directly from the Dispatchable object?

Reason 1: this is high coupling and low cohesion, which we rather not want.
Reason 2: data encapsulation.
You should now implement the methods provided in the IDispatchable interface.
Hide Copy Code
///
/// The handle event of the dispatchable
///
/// the event to handle
public void HandleEvent(IEvent ievent)
{
Debug.Assert(ievent != null);

if (ievent is FlyEvent)
{

Register the IDispatchable at the dispatcher (the Bird does this in its constructor).
Hide Copy Code
///
/// Constructor
///
public Bird()
{
// this will register the Bird
Dispatcher.GetInstance.Register(this);
}
What does this Dispatcher do?

The heart of the Proactor Pattern is the Dispatcher. This Dispatcher dispatches the enqueued events to the registered Dispatchables in a (separate) thread.

Hide Copy Code
///
/// Dispatches the events to the dispatchable items
///
private void Dispatch()
{
// thread must be running.
while (_dispachThread.ThreadState == System.Threading.ThreadState.Running)
{
// wait for signal
_autoResetEvent.WaitOne();

      // the queue should have at least one queue item available
      if( _queue.Count >= 1 )
      {

The Dispatcher is a Singleton.

Hide Copy Code
///
/// This method will return the Dispatchers instance
/// This is a Singleton pattern.
///
public static Dispatcher GetInstance
{
get
{
lock (_instanceLock)
{
// if the instance exists, then return the
// already created disptacher
if (_instance == null)
{
// first time for the singleton
_instance = new Dispatcher();
}
return _instance;
}
}
}
Keep in mind that events with a higher priority will be dispatched first. Be careful not to create starvation.

Example:

Time x: The Dispatcher’s queue contains 210938 events with priority “Very High”.

Time x + 1 millisecond: A “Very Low” priority event has been enqueued (and no further events will be enqueued).

Time x + 32365 milliseconds: the Dispatcher’s queue still contains 21 events with a priority “Very High”.

The event enqueued at (Time + 1 ms) could be outdated. Don’t get disappointed. There are mechanisms to prevent starvation, like a dynamic priority queue. The best part of having your own event handling mechanism is that such problems become suddenly…a challenge.

Get the Dispatcher’s instance.
Create an event and enqueue it to the Dispatcher. Decide the priority level of the event to enqueue.
Hide Copy Code
// event fired to the eagle
FlyEvent fly = new FlyEvent();
Dispatcher.GetInstance.Enqueue(_eagle.DISPATCHABLE_ID,
fly, Dispatcher.Priority.Normal );
Don’t do
Do not process too much in the HandleEvent of the Dispatcher.
For the heroes, don’t be pessimistic prematurely.
To be continued
This Proactor Pattern could be extended with multiple patterns. I’ll wait on the responses first before I make a “Part 2” of this Pattern.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值