2.WF4中工作流的执行原理
首先要明确,在WF4中,如果使用WorkflowInvoker类来启动工作流时:
工作流Workflow1将在调用者的线程中执行。这种情况下,工作流的执行类似于方法调用,是最简单的执行模式。
然而,如果使用WorkflowApplication启动工作流,工作流实例将在调用者线程之外的另一个线程中运行:
wpp.Run();
而且,这个“另外的工作线程”是线程池中的线程。
不管是由哪个线程负责执行工作流,有一个原则是很重要的:
单个工作流实例是单线程执行的,哪怕诸如Parallel Activity给你一个多分支“并行”运行的假象。
事实上,Parallel Activity采用在单线程中“轮换执行”各分支。当一个分支进入空闲“Idle”时,工作流调度器调度下一分支投入运行。所果所有分支都不包括使本分支进入Idle状态的Activtity(比如有一个Delay Activity或创建了书签),则Parallel Activity按从左到右的顺序执行各分支。
那么,构成工作流的各个Activity实例是如何执行的?
WF运行时在内部为每个工作流维护了一个工作项队列。然后,创建一个Scheduler类的实例来负责从此工作项队列中取出和追加工作项,并执行之。
这里要说说这个工作项队列,在Scheduler类的代码中可以找到它的声明:
这里有一个奇怪的Quack
Quack<T>
初始时,为队列分配可容纳4个T类型对象的内存空间,当不断增加对象而需要扩充空间时,就分配一个“当前所占内存空间*2”的新数组,再将老数组中的内容复制到新数组中。
很明显,在两个数组中复制元素会花费系统资源,我不知道为何WF4的设计者这样设计,估计是他们有其他的考虑。
队列中的WorkItem对象很有趣,它代表一个将被执行的Activity实例,这里暂时放下,一会儿还会介绍它。
Scheduler对象的工作可以简述如下:
它从队列中取出一个WorkItem对象,然后将其委托给线程池中的线程(如果工作流由WorkApplication以异步方式启动执行)或调用者线程(如果工作流由WorkflowInvoker以同步方式启动执行)执行。这些线程将负责调用WorkItem所封装的Activity实例的Execute()方法(或类似的方法,如前所述)。