论坛首页 Java版

如何实现一个性能高的解释器?

浏览 11128 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
最后更新时间:2006-01-25
静态有类型语言处理复杂业务逻辑上灵活性太低,
相信很多人都有类似的体会,
哪我们何不在用静态的宿主语言写一个动态的解释器去用自己定义的简单的动态脚本实现复杂的业务逻辑呢?
虽然java有beanshell,
但是我相信一定用了反射机制来做的,
不适用与非有反射机制的语言

考虑到C++是一门强类型语言,
处理复杂业务逻辑的灵活性不够,
因此考虑写无类型的动态脚本,用宿主语言C++写个脚本解释器,
处理复杂的业务逻辑


挑选费用的计算逻辑考虑解决方案,
由于C++RTTI机制比java反射机制灵活度差很多,
因此挑选map实现字段与与字段串名之间的对应
此问题C++问题等价与不用java的反射机制,
也就是强类型语言如何解决此类问题

#include <iostream>
#include <map>


class FeeArray
{
public:
FeeArray(){}
int fee1;
int fee2;
int fee3;
int fee4;
int fee5;
int fee6;
int fee7;
int fee8;
//... ...
//总共有80多个费用字段

};


class CalFldMap
{
std::map<std::string, int> fldMap;

public:
CalFldMap(){}

~CalFldMap(){}

int getFldVal( const std::string & name ){ return
fldMap[ name ]; }

void setFldVal( const std::string & name, int val ){
fldMap[ name ] = val; }

void mapToEntity( FeeArray & array ){
array.fee1 = fldMap[ "fee1" ];
array.fee2 = fldMap[ "fee2" ];
array.fee3 = fldMap[ "fee3" ];
array.fee4 = fldMap[ "fee4" ];
array.fee5 = fldMap[ "fee5" ];
array.fee6 = fldMap[ "fee6" ];
array.fee7 = fldMap[ "fee7" ];
array.fee8 = fldMap[ "fee8" ];

//... ...
//总共有80多个费用字段
}
void initFromEntity( const FeeArray & array ){
fldMap[ "fee1" ] = array.fee1;
fldMap[ "fee2" ] = array.fee2;
fldMap[ "fee3" ] = array.fee3;
fldMap[ "fee4" ] = array.fee4;
fldMap[ "fee5" ] = array.fee5;
fldMap[ "fee6" ] = array.fee6;
fldMap[ "fee7" ] = array.fee7;
fldMap[ "fee8" ] = array.fee8;

//... ...
//总共有80多个费用字段

}
};


class CalCulatorEgine{
public:
static void cal( CalFldMap & fldMap, string expr ){
//calculate logic
}
}


int main(){
FeeArray feearray;
feearray.fee1 = 123;
feearray.fee2 = 456;

CalFldMap fldMap;
fldMap.initFromEntity( feearray );

//此运算串配置在数据库中如果业务逻辑多变,
可以从数据库更改下面串

//此程序的用户可能有n个,每个用户的此计算脚本也就在数据库有不同的配置

string calstr =
"if(fee1 > 5000 && fee1 < 50000)" +
" fee2=50                 " +
"elif(fee1 > 50000)             " +
" fee2=100                " +
"else                           " +
" fee2=100                " +
"fee3=fee2*3/10                 " +
"fee4=fee2*3/10                 " +
"fee5=fee2*3/10                 " +
"fee6=fee2-(fee3+fee4+fee5)     " ;

CalCulatorEgine::cal( fldMap, calstr );
}


重点问题是如何实现一个高性能的CalCulator,也就是一个高性能的解释器也就是expr的高性能解释问题
偷懒参考了TCPPPL的计算器实现了一个解释器, 将CalFldMap
& fldMap跟计算器的运算环境表的env合并一起,没有if
else逻辑, 测试了一下性能太低,
只是执行解释传200 0000简单的算式就需要200s
但是这对于处理几百万笔处理时间要控制在10分钟左右的系统性能差太多
毕业于数学系, 惭愧, 不大懂编译原理
考虑来考虑去, 最终还是决定把帖子发上来,
因为找不到其他地方可以发,
很难找到象javaeye一样高手如云的地方
虽然是C++写的,但是理念无界限
   
最后更新时间:2006-01-25
找个现成的脚本语言,譬如ruby之类的。
   
0 请登录后投票
最后更新时间:2006-01-26
我如果用ruby或者perl, python之类的语言, 如何把其计算出的值跟宿主语言C++的对象之间的值进行映射?
而且, 不知道ruby等动态语言有没有提供供C++,java调用的接口?否则两种语言的运行context来回切换性能也不会高
   
0 请登录后投票
最后更新时间:2006-01-26
就像JAVA beanshell一样, 没看过beanshell的源码, 估计用到了反射机制才跟java的对象之间的值进行映射对应。
但是这不适用用于大多数面向对象的语言, 对于C++, 可以写一个类似beanshell的框架, 可以提供一个抽象类

class EntityScriptMapper
{
std::map<std::string, int> fldMap;

public:
CalFldMap(){}

~CalFldMap(){}

int getFldVal( const std::string & name ){ return fldMap[ name ]; }

void setFldVal( const std::string & name, int val ){ fldMap[ name ] = val; }

virtual void mapToEntity( FeeArray & array ) = 0;
/*{
array.fee1 = fldMap[ "fee1" ];
array.fee2 = fldMap[ "fee2" ];
array.fee3 = fldMap[ "fee3" ];
array.fee4 = fldMap[ "fee4" ];
array.fee5 = fldMap[ "fee5" ];
array.fee6 = fldMap[ "fee6" ];
array.fee7 = fldMap[ "fee7" ];
array.fee8 = fldMap[ "fee8" ];

//... ...
//总共有80多个费用字段
}*/
virtual void entityToScriptConext( const FeeArray & array ) = 0;
/*{
fldMap[ "fee1" ] = array.fee1;
fldMap[ "fee2" ] = array.fee2;
fldMap[ "fee3" ] = array.fee3;
fldMap[ "fee4" ] = array.fee4;
fldMap[ "fee5" ] = array.fee5;
fldMap[ "fee6" ] = array.fee6;
fldMap[ "fee7" ] = array.fee7;
fldMap[ "fee8" ] = array.fee8;

//... ...
//总共有80多个费用字段

}*/
};

用户只多实现一个抽象类, 应该也可一做出象beanshell的东西。
另外不知道beanshell的性能如何
   
0 请登录后投票
最后更新时间:2006-01-26
用Groovy吧,丫跟它老爸爸java是一个血脉.
   
0 请登录后投票
最后更新时间:2006-01-26
怎么回答都跟提问相违背。
Groovy跟beanshell一样, 语言局限性太强, 跟java绑定很死, 对于没反射机制的语言, 而且性能肯定不行
   
0 请登录后投票
最后更新时间:2006-01-27
楼主你好歹先 profile 一下,看看性能瓶颈究竟在哪边好不好?顺便也把你大致的需求列一列,看看你这情况是不是真的非要做个自己的解释器不可。
   
0 请登录后投票
最后更新时间:2006-01-28
刚到老家SD, 法师有The C++ programming language 这本书么? 我就是用的那上面的计算器做的,随便造个简单的算式,300 0000个式子解释要几十分钟,距离几分钟的性能要求相距甚远, 解释性能低的实在可怜, 可能需要创建一种便于高性能解释的语法(我觉得象Lisp这种, 只需要数学运算逻辑跟if else逻辑的子集), 可是对编译这东西研究的太少, 一时不知道如何下手去做
   
0 请登录后投票
最后更新时间:2006-02-05
回来了, 有没有熟悉编译原理,算法的强人 ?
   
0 请登录后投票
最后更新时间:2006-02-07
zengjin8310 写道
刚到老家SD, 法师有The C++ programming language 这本书么? 我就是用的那上面的计算器做的,随便造个简单的算式,300 0000个式子解释要几十分钟,距离几分钟的性能要求相距甚远, 解释性能低的实在可怜, 可能需要创建一种便于高性能解释的语法(我觉得象Lisp这种, 只需要数学运算逻辑跟if else逻辑的子集), 可是对编译这东西研究的太少, 一时不知道如何下手去做


你只是纯粹地要优化表达式解析么?那么把代码和你试验的例子上传来看看吧。说起来,30M 个表达式解析要几分钟搞定,如果表达式复杂的话也是有点难度的。嗯嗯,不过从你前面的描述来看,我想对于一个用户来说要做的计算是一样的吧?应该是同样的计算对不同的记录做很多次这样一个模式,那么应该可以玩玩“JIT”,呵呵。
   
0 请登录后投票
论坛首页 Java版

跳转论坛:
JavaEye推荐