技术开发 频道

探秘WF4 Beta2中工作流对象模型

  2.WF4中工作流的执行原理

  首先要明确,在WF4中,如果使用WorkflowInvoker类来启动工作流时:

WorkflowInvoker.Invoke(new Workflow1());

        工作流Workflow1将在调用者的线程中执行。这种情况下,工作流的执行类似于方法调用,是最简单的执行模式。

  然而,如果使用WorkflowApplication启动工作流,工作流实例将在调用者线程之外的另一个线程中运行:

WorkflowApplication wpp = new WorkflowApplication(new Workflow1());  
wpp.Run();

        而且,这个“另外的工作线程”是线程池中的线程。

  不管是由哪个线程负责执行工作流,有一个原则是很重要的:

  单个工作流实例是单线程执行的,哪怕诸如Parallel Activity给你一个多分支“并行”运行的假象。

  事实上,Parallel Activity采用在单线程中“轮换执行”各分支。当一个分支进入空闲“Idle”时,工作流调度器调度下一分支投入运行。所果所有分支都不包括使本分支进入Idle状态的Activtity(比如有一个Delay Activity或创建了书签),则Parallel Activity按从左到右的顺序执行各分支。

  那么,构成工作流的各个Activity实例是如何执行的?

  WF运行时在内部为每个工作流维护了一个工作项队列。然后,创建一个Scheduler类的实例来负责从此工作项队列中取出和追加工作项,并执行之。

  这里要说说这个工作项队列,在Scheduler类的代码中可以找到它的声明:

private Quack<WorkItem> workItemQueue;

       这里有一个奇怪的Quack泛型类,我仔细看了一下,其实它就是一个泛型队列,但它有一点特殊之处:

  Quack<T>泛型类在内部使用一个数组来保存数据:

private T[] items;

       初始时,为队列分配可容纳4个T类型对象的内存空间,当不断增加对象而需要扩充空间时,就分配一个“当前所占内存空间*2”的新数组,再将老数组中的内容复制到新数组中。

  很明显,在两个数组中复制元素会花费系统资源,我不知道为何WF4的设计者这样设计,估计是他们有其他的考虑。

  队列中的WorkItem对象很有趣,它代表一个将被执行的Activity实例,这里暂时放下,一会儿还会介绍它。

  Scheduler对象的工作可以简述如下

  它从队列中取出一个WorkItem对象,然后将其委托给线程池中的线程(如果工作流由WorkApplication以异步方式启动执行)或调用者线程(如果工作流由WorkflowInvoker以同步方式启动执行)执行。这些线程将负责调用WorkItem所封装的Activity实例的Execute()方法(或类似的方法,如前所述)。

0