`
ahuaxuan
  • 浏览: 633698 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

土制状态机在工作流引擎中的应用

阅读更多
/**
  * @author : ahuaxuan
  * @date 2009-10-27
  */

很早之前(应该是一年以前),ahuaxuan在用dfa实现文字过滤一文中使用确定有限自动机实现了词典的高速查询。其实在当时那段时间里,由于对状态机有了一定的研究,ahuaxuan也触类旁通的理解了工作流引擎的核心体制。于是当时就用python写了一个小巧的工作流引擎的示例,在这之前ahuaxuan没有看过任何工作流引擎的实现,该实现纯属思维的自我延伸。

现在我来说说我的实现。
状态机的本质是状态的迁移,即从A状态+某个动作===》B状态。到这里我们还要来看看这张图。

从这张图中我们可以看到,状态(大写字母)+动作(小写字母)可以到达新的状态。那么对于程序员来说,我们要做的就是将这种机制用程序表达出来。比如说我们最常想到的是什么?矩阵!

这很好理解,但是对于工作流引擎来说,由于状态的迁移涉及到:当前状态+动作+条件===》新状态。
所以用二维的矩阵无法表示出这种逻辑。那么我们可以将矩阵中的元素替换为条件数组。
这样,我们可以通过当前状态+动作得到一个条件数组,然后再遍历这个条件数组,条件数组中的元素即是条件和满足条件的下一个状态(虽然本质上是一个三维数组,但是在这里还是看成矩阵+数组元素比较符合逻辑)。



这里需要画一个图,一个矩阵,矩阵中的元素是一个条件数组

没错,这是一种方案,但是这里有一个问题,那就是每次做状态迁移的时候,我们必须知道某个状态在矩阵一维上的index,已经某个动作在矩阵二维上的index.有了这两个index我们才能得到条件数组。所以这里还有一个繁琐的转换操作操作。来看一段伪代码:
conditions = matrix[getStatusIndex[‘A’], getActionIndex[‘a’]]
For condiction in conditions:
       If condition match input:
              Return Condition.nextStatus


核心流程大概就是这样,当

那么除了矩阵这种数据结构,我们还有其他的数据结构可以用来表示: “当前状态+动作+条件===》新状态”吗。

当然有,那就是使用树结构。在了解了三维数组的实现之后,再来看树实现,应该和容易了,那就直接上图, 将上图的矩阵转换成树结构之后,我们可以得到如下的树结构。



那现在我们来审视一下现在的问题,打个比方,我们现在手里有两张牌,一张是状态A,一张是动作a,我们如何通过这两种牌来得到条件集合呢,最简单的方法是首先遍历第二层节点,找到A,然后再遍历A的子节点,找到a。通过两次for循环找到了条件集合,而条件集合中包含着下一个状态。

那么有没有更简单更快速的方式可以直接找到条件集合,而直接跳过两次遍历呢。有,ahuaxuan的想法是tree+hash.也就是通过A的hash值,我们可以直接找到tree上的A节点。然后再通过a的hash值,我们可以直接找到A的子中的a节点。得到a节点之后我们就可以条件集合。那么我们可以用什么样的数据结构来实现一个这样的模型呢。这里面有hash运算,那么我们首先选择HashMap来创建这么一颗树。

我们来看一下这个定义:
Map<String, Map<String, Map<String, List<Transition>>>> dfa。


那么我们如何根据A,和a来得到一个条件集合呢?
Dfa.get[“processName”].get[“A”].get[“a”]
通过这样的方式,我们就可以根据当前状态和当前的动作得到一个条件集合。然后遍历这个条件集合就是找到满足“输入“的条件,该条件会指向下一个状态。

我们来看一下代码实现:
首先我们来构造这么一个状态机:
private void constructDfa(List<WfProcess> processList) {
		for (WfProcess pro : processList) {
			Map<String, Map<String, List<Transition>>> pmap = new HashMap<String, Map<String,List<Transition>>>();
			dfa.put(pro.getName(), pmap);
			
			for (State sta : pro.getStates()) {
				Map<String, List<Transition>> smap = new HashMap<String, List<Transition>>();
				pmap.put(String.valueOf(sta.getName()), smap);
				
				for (Action action : sta.getActions()) {
					List<Transition> transitions = new ArrayList<Transition>();
					for (String transName : action.getTransNames()) {
						transitions.add(pro.getTransitions().get(transName));
					}
					
					smap.put(String.valueOf(action.getName()), transitions);
				}
				
			}
		}
	}


接着我们来看看如何根据这个状态机来做状态迁移:

public String getNextState(String processName, String stateId, String actionId, Map<String, String> conditions) {
		
		List<Transition> transitions = dfa.get(processName).get(String.valueOf(stateId)).get(String.valueOf(actionId));
		
		for (Transition trans : transitions) {
			if (match(trans.getConditions(), conditions)) {
				return trans.getToState();
			}
		}
		
		StringBuilder sb = new StringBuilder();
		sb.append("There is no state for process : ").append(processName);
		sb.append(", stateId : ").append(stateId);
		sb.append(", actionId : ").append(actionId);
		sb.append(", conditions : ").append(conditions);
		
		throw new WorkFlowStateException(sb.toString());
	}


通过这种tree + hash的方式,我们可以很容易的进行状态的迁移,不需要那么多for循环。但是for循环确实有这样的实现。

今天早上下载了osworkflow的代码,稍微看了一下AbstractWorkflow的doAction方法。
发现osworkflow就是通过循环来实现状态的迁移的,比如说上图中树结构的状态可以用以下伪代码:
For state in states:
	If state.name == inputStateName:
		For action in state.actions:
			If action.name == inputActionName:
					for transition in action.transitions:
	…………………………………………………………………



通过这种方式,用户传入inputStateName和inputActionName, osworkflow得到了一组transition,并根据条件选择某个transition, 这样也实现了状态的转移。

从这里面可以看出,osworkflow是利用广度优先的原则,先找到符合条件的state,然后再找到符合条件的action,以此类推。

说到这里,通过这种状态机实现工作流引擎的方式基本的完全的,较为清晰的呈现在我们眼前了。

未完待续

  • 大小: 16.2 KB
  • 大小: 21.8 KB
4
0
分享到:
评论
2 楼 ahuaxuan 2009-11-02  
把动作和条件合并在一起的做法不太流行


动作是一个操作,条件是对业务数据的一个抽象。
比如动作是一个类的方法,而条件是方法的参数决定的,这样更合理一些
1 楼 melin 2009-11-02  
打算写一个小的工作流引擎:
定义的流程定义为:
<processdefine name="TestFlow" version="1.1.1" description="">
	<Activitys>
		<Activity id="start" type="start" name="开始" description="">
			<SplitMode>XOR</SplitMode>
		</Activity>
		<Activity id="A01" type="manual" name="申请" description="">
			<SplitMode>XOR</SplitMode>
			<JoinMode>XOR</JoinMode>
			<participantType>organization</participantType>
			<participantList>
				<participant id="910150" name="俞文琦" type="person"/>
				<participant id="910115" name="李强" type="person"/>	
			</participantList>
		</Activity>
		<Activity id="A02" type="manual" name="审核" description="">
			<SplitMode>XOR</SplitMode>
			<JoinMode>XOR</JoinMode>
			<participantType>process-starter</participantType>
		</Activity>
		<Activity id="end" type="finish" name="结束" description="">
			<JoinMode>XOR</JoinMode>
		</Activity>
	</Activitys>
	
	<Transitions>
		<Transition id="" from="start" to="A01" name="">
			<IsDefault>true</IsDefault>
		</Transition>
		<Transition id="" from="A01" to="A02" name="">
			<IsDefault>true</IsDefault>	
		</Transition>
		<Transition id="" from="A02" to="end" name="">
			<IsDefault>false</IsDefault>
			<Expression>optId==1</Expression>
		</Transition>
	</Transitions>
</processdefine>


查找当前环节的后续环节为:
public Transition[] getNextTransitions(String aid) {
		Transition[] arr = null;
		List<Transition> list = new ArrayList<Transition>();
		Iterator<Transition> it = this.transitions.iterator();
		while (it.hasNext()) {
			Transition trans = it.next();
			if (trans.getFrom().equals(aid))
				list.add(trans);
		}
		arr = new Transition[list.size()];
		for (int i = 0; i < arr.length; ++i) {
			arr[i] = ((Transition) list.get(i));
		}
		return arr;
	}


查找满足条件的transition
public static List<String> getPossilbeListNormal(WFProcessInstance pi,
			Activity actDef, Transition[] transarr) {
		List<String> possibleList = new ArrayList<String>(4);

		if (actDef.getSplitMode().equals("AND")) {
			for (int i = 0; i < transarr.length; ++i) {
				possibleList.add(transarr[i].getTo());
			}
		} else {
			Transition[] oktrans;
			int i;
			if (actDef.getSplitMode().equals("XOR")) {
				oktrans = getXORModeNextTrans(transarr, pi.getRelDataMap());

				Transition tran = findMostOKByPrority(oktrans);

				possibleList.add(tran.getTo());
			} else if (actDef.getSplitMode().equals(DefineConst.SPLIT_MODE_OR)) {
				oktrans = getORModeNextTrans(transarr, pi.getRelDataMap());

				if (oktrans.length == 0) {
					return possibleList;
				}

				for (i = 0; i < oktrans.length; ++i) {
					possibleList.add(oktrans[i].getTo());
				}

			}

		}

		return possibleList;
	}

相关推荐

    论文研究 - 生土的NaOH活化:NaOH含量对干燥动力学的影响及其建模

    这项工作旨在确定氢氧化钠浓度对用生黏土制得的砖的干燥动力学的影响,并对该动力学进行建模。 结果表明,由于缺乏游离水,干燥动力学受水的扩散控制。 干燥时间随NaOH含量的增加而线性增加,而体积收缩率则下降,...

    硅藻土制备介孔SiO2气凝胶 (2013年)

    采用响应面法对由硅藻土制取水玻璃的工艺进行优化,进而选择最佳工艺参数在常压干燥下成功合成了SiO2气凝胶材料。试验结果表明:当碱硅比为3∶10,NaOH溶液浓度为10%,反应温度为90℃时,水玻璃模数测定值与SiO2溶出...

    不同材料的生态混凝土对污水净化效果的比较 (2011年)

    为比较不同材料所制成的多孔混凝土对有机污水净化的效果,采用了不同的材料来制作3种混凝土反应柱,一为普通硅酸盐水泥与粗砂制作的混凝土,二为复合硅酸盐水泥与粗砂制作的混凝土,三为复合硅酸盐水泥与红粘土制 作的...

    基于深度学习的零样本识别.zip

    基于深度学习的零样本识别.zip

    《大数据原理》LSH算法实现

    用map-reduce的形式实现了LSH算法

    Text-2024-05-09 17-11-33.txt

    Text-2024-05-09 17-11-33.txt

    node-v6.14.4-linux-armv6l.tar.xz

    Node.js,简称Node,是一个开源且跨平台的JavaScript运行时环境,它允许在浏览器外运行JavaScript代码。Node.js于2009年由Ryan Dahl创立,旨在创建高性能的Web服务器和网络应用程序。它基于Google Chrome的V8 JavaScript引擎,可以在Windows、Linux、Unix、Mac OS X等操作系统上运行。 Node.js的特点之一是事件驱动和非阻塞I/O模型,这使得它非常适合处理大量并发连接,从而在构建实时应用程序如在线游戏、聊天应用以及实时通讯服务时表现卓越。此外,Node.js使用了模块化的架构,通过npm(Node package manager,Node包管理器),社区成员可以共享和复用代码,极大地促进了Node.js生态系统的发展和扩张。 Node.js不仅用于服务器端开发。随着技术的发展,它也被用于构建工具链、开发桌面应用程序、物联网设备等。Node.js能够处理文件系统、操作数据库、处理网络请求等,因此,开发者可以用JavaScript编写全栈应用程序,这一点大大提高了开发效率和便捷性。 在实践中,许多大型企业和组织已经采用Node.js作为其Web应用程序的开发平台,如Netflix、PayPal和Walmart等。它们利用Node.js提高了应用性能,简化了开发流程,并且能更快地响应市场需求。

    基于springboot的电影院订票管理系统

    开发语言:Java JDK版本:JDK1.8(或11) 服务器:tomcat 数据库:mysql 5.6/5.7(或8.0) 数据库工具:Navicat 开发软件:idea 依赖管理包:Maven 代码+数据库保证完整可用,可提供远程调试并指导运行服务(额外付费)~ 如果对系统的中的某些部分感到不合适可提供修改服务,比如题目、界面、功能等等... 声明: 1.项目已经调试过,完美运行 2.需要远程帮忙部署项目,需要额外付费 3.本项目有演示视频,如果需要观看,请联系我v:19306446185 4.调试过程中可帮忙安装IDEA,eclipse,MySQL,JDK,Tomcat等软件 重点: 需要其他Java源码联系我,更多源码任你选,你想要的源码我都有! https://img-blog.csdnimg.cn/direct/e73dc0ac8d27434b86d886db5a438c71.jpeg

    基于深度学习的舌象诊断系统源码+文档说明.zip

    基于深度学习的舌象诊断系统源码+文档说明.zip

    2023-04-06-项目笔记 - 第一百二十八阶段 - 4.4.2.126全局变量的作用域-126 -2024.05.09

    2023-04-06-项目笔记-第一百二十八阶段-课前小分享_小分享1.坚持提交gitee 小分享2.作业中提交代码 小分享3.写代码注意代码风格 4.3.1变量的使用 4.4变量的作用域与生命周期 4.4.1局部变量的作用域 4.4.2全局变量的作用域 4.4.2.1全局变量的作用域_1 4.4.2.126全局变量的作用域_126 - 2024-05-09

    深度学习入门-基于python的理论与实现.zip

    深度学习入门-基于python的理论与实现.zip

    基于python的气象数据处理

    数据处理 |--- 处理气象数据(nc文件) 操作说明: nc 文件命名为:deal_nc.nc,放到data目录下 1、 执行parse_nc.py,解析nc文件,同时在data目录下生成.npy数据文件 2、 执行draw_data.py ,获取.npy数据,并绘制图形

    TPE5608通讯管理机底层

    TPE5608通讯管理机底层

    机器学习,深度学习基础模型实现,基础组件,便于快速复用与集成.zip

    机器学习,深度学习基础模型实现,基础组件,便于快速复用与集成.zip

    node-v6.5.0-linux-ppc64le.tar.xz

    Node.js,简称Node,是一个开源且跨平台的JavaScript运行时环境,它允许在浏览器外运行JavaScript代码。Node.js于2009年由Ryan Dahl创立,旨在创建高性能的Web服务器和网络应用程序。它基于Google Chrome的V8 JavaScript引擎,可以在Windows、Linux、Unix、Mac OS X等操作系统上运行。 Node.js的特点之一是事件驱动和非阻塞I/O模型,这使得它非常适合处理大量并发连接,从而在构建实时应用程序如在线游戏、聊天应用以及实时通讯服务时表现卓越。此外,Node.js使用了模块化的架构,通过npm(Node package manager,Node包管理器),社区成员可以共享和复用代码,极大地促进了Node.js生态系统的发展和扩张。 Node.js不仅用于服务器端开发。随着技术的发展,它也被用于构建工具链、开发桌面应用程序、物联网设备等。Node.js能够处理文件系统、操作数据库、处理网络请求等,因此,开发者可以用JavaScript编写全栈应用程序,这一点大大提高了开发效率和便捷性。 在实践中,许多大型企业和组织已经采用Node.js作为其Web应用程序的开发平台,如Netflix、PayPal和Walmart等。它们利用Node.js提高了应用性能,简化了开发流程,并且能更快地响应市场需求。

    node-v7.0.0-linux-armv7l.tar.xz

    Node.js,简称Node,是一个开源且跨平台的JavaScript运行时环境,它允许在浏览器外运行JavaScript代码。Node.js于2009年由Ryan Dahl创立,旨在创建高性能的Web服务器和网络应用程序。它基于Google Chrome的V8 JavaScript引擎,可以在Windows、Linux、Unix、Mac OS X等操作系统上运行。 Node.js的特点之一是事件驱动和非阻塞I/O模型,这使得它非常适合处理大量并发连接,从而在构建实时应用程序如在线游戏、聊天应用以及实时通讯服务时表现卓越。此外,Node.js使用了模块化的架构,通过npm(Node package manager,Node包管理器),社区成员可以共享和复用代码,极大地促进了Node.js生态系统的发展和扩张。 Node.js不仅用于服务器端开发。随着技术的发展,它也被用于构建工具链、开发桌面应用程序、物联网设备等。Node.js能够处理文件系统、操作数据库、处理网络请求等,因此,开发者可以用JavaScript编写全栈应用程序,这一点大大提高了开发效率和便捷性。 在实践中,许多大型企业和组织已经采用Node.js作为其Web应用程序的开发平台,如Netflix、PayPal和Walmart等。它们利用Node.js提高了应用性能,简化了开发流程,并且能更快地响应市场需求。

    医院机房建设清单明细及报价.xls

    文章摘要 智慧医院智能化系统建设方案旨在通过智能化手段提升医院的安全性、舒适性、便捷性和效率。该方案规划了四大类子系统:平台、应用、节能和安全,以打造一个高效的医疗环境。 信息设施系统:包括综合布线系统、信息网络系统、多媒体会议系统等,旨在为医院提供稳定、高速的网络服务。综合布线系统采用6类非屏蔽铜缆和光纤,支持多种业务信息的传输。信息网络系统采用以太网交换技术和树型网络结构,确保网络的稳定性和安全性。 信息化应用系统:包括信息查询系统、分诊排队叫号系统、ICU探视系统等,通过信息技术提高医疗服务的质量和效率。信息查询系统便于病员及家属查询医院信息,分诊排队叫号系统优化就诊流程,ICU探视系统通过音视频技术实现远程探视和监护。 安全防范系统:针对医患关系敏感、医疗纠纷、医护人身安全等问题,设计了安防音视频监控系统、电子巡更系统、门禁系统等,以提高医院的安全管理水平。安防音视频监控系统在关键区域设置监控摄像机,电子巡更系统确保巡更人员按时按路线完成任务,门禁系统通过权限管理控制人员出入。 机房建设工程:包括机房配电系统、防雷接地系统、消防系统等,确保机房设备的安全稳定运行。机房供配电系统采用普通电源和不间断电源,消防系统采用无管网七氟丙烷气体灭火系统,防雷系统采用三级防雷措施,机房空调系统保持适宜的温度和湿度。 方案特色:紧扣标准、安全简便、统一融合、可视操作、事前预防、智能管控。通过智能化系统的设计和实施,医院能够更有效地进行安全管理,提高医疗服务质量,同时降低维护成本和提升运营效率。

    da_1715269209522..apk

    da_1715269209522..apk

    node-v6.9.5-linux-s390x.tar.xz

    Node.js,简称Node,是一个开源且跨平台的JavaScript运行时环境,它允许在浏览器外运行JavaScript代码。Node.js于2009年由Ryan Dahl创立,旨在创建高性能的Web服务器和网络应用程序。它基于Google Chrome的V8 JavaScript引擎,可以在Windows、Linux、Unix、Mac OS X等操作系统上运行。 Node.js的特点之一是事件驱动和非阻塞I/O模型,这使得它非常适合处理大量并发连接,从而在构建实时应用程序如在线游戏、聊天应用以及实时通讯服务时表现卓越。此外,Node.js使用了模块化的架构,通过npm(Node package manager,Node包管理器),社区成员可以共享和复用代码,极大地促进了Node.js生态系统的发展和扩张。 Node.js不仅用于服务器端开发。随着技术的发展,它也被用于构建工具链、开发桌面应用程序、物联网设备等。Node.js能够处理文件系统、操作数据库、处理网络请求等,因此,开发者可以用JavaScript编写全栈应用程序,这一点大大提高了开发效率和便捷性。 在实践中,许多大型企业和组织已经采用Node.js作为其Web应用程序的开发平台,如Netflix、PayPal和Walmart等。它们利用Node.js提高了应用性能,简化了开发流程,并且能更快地响应市场需求。

Global site tag (gtag.js) - Google Analytics