论坛首页 Java企业应用论坛

FEL(表达式语言)——7月30号更新

浏览 13242 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2011-03-17   最后修改:2011-03-17
曾经想过短变量使用intern放到常量池然后用==比较,但是intern更不靠谱(实际上intern也内置了字符串比较:和常量池已有内容比较)。

这里可以采用一个折衷方案,就是用
int keyHashCode = key.hashCode(),key1HashCode = "a".hashCode();
if(keyHashCode == key1HashCode&&"a".equals(keyHashCode){
xxx
};
这种形式能大致保证只比较判断一次字符串。
我现在就改造下试试。
--------------改完了,性能约提升1倍

14000+ 到 4000+的改变



package calc.util;

import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;

public abstract class MapperCreator implements Opcodes{
	protected double[] data;
	public  static Class<? extends Mapper> createMapperBean(String[] propertyNames) throws Exception{
		return createMapperBean(propertyNames, "fl.calc.MapperBean");
	}
	private static Class<? extends Mapper> createMapperBean(String[] propertyNames,final String className ) throws Exception{
		// 類頭
		String[] itfs = {Mapper.class.getName().replace(".", "/")};//注意:接口名中的.要替換成/
		ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
		String slashedClassName = className.replace(".", "/");
		cw.visit(V1_5, ACC_PUBLIC, slashedClassName,null, "java/lang/Object", itfs);
		cw.visitField(ACC_PUBLIC, "data", "[D",  null, null).visitEnd();  
		// 默認構造方法
		MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
		mv.visitVarInsn(ALOAD, 0);//讀入this
		mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V");//調用默認構造方法中的初始化
		mv.visitVarInsn(ALOAD, 0);//讀入this
		
		int constNum = getConstNum(propertyNames.length);
		if(constNum>=0) {
			mv.visitInsn(constNum);
		} else {
			mv.visitIntInsn(SIPUSH, propertyNames.length);
		}
		mv.visitIntInsn(NEWARRAY,T_DOUBLE);//创建数组
		mv.visitFieldInsn(PUTFIELD, slashedClassName, "data","[D");//为data变量赋值
		mv.visitInsn(RETURN);//函數返回
		mv.visitMaxs(1, 1);
		mv.visitEnd();
		
		mv = cw.visitMethod(ACC_PUBLIC,"getData","()[D",null,null);//getdata方法
		mv.visitVarInsn(ALOAD, 0);//装入this
		mv.visitFieldInsn(GETFIELD, slashedClassName, "data", "[D");//获取到数组
		mv.visitInsn(ARETURN);//返回数组
		mv.visitMaxs(1, 1);
		mv.visitEnd();
		
		mv = cw.visitMethod(ACC_PUBLIC, "put", "(Ljava/lang/String;D)V", null,null);//put方法
		mv.visitVarInsn(ALOAD, 1);
		mv.visitMethodInsn(INVOKEVIRTUAL,"java/lang/String", "hashCode", "()I");
		int currentOffset = 4;
		mv.visitVarInsn(ISTORE, currentOffset++);
		
		for(int i=0;i<propertyNames.length;i++) {
			mv.visitLdcInsn(propertyNames[i].hashCode());
			mv.visitVarInsn(ISTORE, currentOffset++);
		}
		Label exit = new Label();//声明一个label,跳转到结束
		for (int i = 0; i < propertyNames.length; i++) {
			Label next = new Label();
			mv.visitVarInsn(ILOAD, 4);
			mv.visitVarInsn(ILOAD, 5+i);
			mv.visitJumpInsn(IF_ICMPNE, next);
			mv.visitLdcInsn(propertyNames[i]);
			mv.visitVarInsn(ALOAD, 1);
			mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "equals", "(Ljava/lang/Object;)Z");
			mv.visitJumpInsn(IFEQ, next);
			mv.visitVarInsn(ALOAD, 0);
			mv.visitFieldInsn(GETFIELD, slashedClassName, "data", "[D");
			constNum = getConstNum(i);
			if(constNum>=0) {
				mv.visitInsn(constNum);
			} else {
				mv.visitIntInsn(SIPUSH, i);
			}
			mv.visitVarInsn(DLOAD, 2);
			mv.visitInsn(DASTORE);
			mv.visitJumpInsn(GOTO	, exit);
			mv.visitLabel(next);
		}
		mv.visitTypeInsn(NEW, "java/lang/RuntimeException");
		mv.visitInsn(DUP);
		mv.visitLdcInsn("Not defined key.");
		mv.visitMethodInsn(INVOKESPECIAL, "java/lang/RuntimeException", "<init>", "(Ljava/lang/String;)V");
		mv.visitInsn(ATHROW);
		mv.visitLabel(exit);
		mv.visitInsn(RETURN);
		mv.visitMaxs(1, 1);
		mv.visitEnd();
		cw.visitEnd();
		return applyClass(className, cw.toByteArray());
	}
	/**
	 * 优化向堆栈压入Int数据,如果在5以内自动使用常数
	 * @param i
	 * @return
	 */
	private static int getConstNum(int i) {
		int constNum;
		if(i== 0) {
			constNum = ICONST_0;
		} else if(i==1) {
			constNum = ICONST_1;
		} else if(i==2) {
			constNum = ICONST_2;
		} else if(i==3) {
			constNum = ICONST_3;
		} else if(i==4) {
			constNum = ICONST_4;
		} else if(i==5) {
			constNum = ICONST_5;
		} else {
			constNum = -1;
		}
		return constNum;
	}
	
	@SuppressWarnings("unchecked")
	private static Class<? extends Mapper> applyClass(final String className, byte[] bytes) {
		return new ClassLoader() {
			public Class defineClass(byte[]bytes) {
				return defineClass(className,bytes, 0, bytes.length);
			}
		}.defineClass(bytes);
	}
}
0 请登录后投票
   发表时间:2011-03-17  
ppgunjack 写道
原来写这个的时候公司已经用一个叫jbell的库做了实现,但我感觉性能不好,所以自己用的时候重写了实现,做的时候就是尽量规避两个事情:继承,字符串处理
在做计算的时候,尽量都用switch和数字比较来处理逻辑,但对变量这个问题一直想不出合适方案,总会在某个地方引入循环内调用的字符串函数

动态编译的东西如果没有继承或者接口,就只能通过反射调用,这种情况更慢,这也是动态编译的一个硬伤。
事实证明,invokespecial要比invokevirtual和invokeinterface快多了。但是真的没办法- -
0 请登录后投票
   发表时间:2011-03-17  
很有启发性,如果可以扩展String加个唯一id作为成员,再加上个全局id生成器那事情就简单多了,台面用字符串,台下用数字,也不用每次算hash
0 请登录后投票
   发表时间:2011-03-17  
 hash_map<const char*, double, hash<const char*> > myMap;
    myMap.insert(make_pair("kpi1",434.232));
    myMap.insert(make_pair("kpi2",323.232));
    myMap.insert(make_pair("kpi3",-232.322));
    myMap.insert(make_pair("kpi4",23.344));
    myMap.insert(make_pair("kpi5",-65566.23));
    myMap.insert(make_pair("kpi6",-4334.2323));
    myMap.insert(make_pair("kpi7",432242));
    //cout<<(myMap.find("kpi1"))->second<<endl;
    int num=100000000;

    cout<<showCurrentTime()<<endl;
    for (int i=0;i<num;i++) {
        myMap.find("kpi1");
        myMap.find("kpi2");
        myMap.find("kpi3");
        myMap.find("kpi4");
        myMap.find("kpi5");
        myMap.find("kpi6");
        myMap.find("kpi7");
    }
    cout<<showCurrentTime()<<endl;

回来想看看gcc的hash_map的速度,mingw4.4.0跑下来花了36秒,晕,明天找个linux再试试
0 请登录后投票
   发表时间:2011-03-18  
你算的是取出的时间吗?。。
0 请登录后投票
   发表时间:2011-03-18  
对,只算取出时间,而且只是运行到返回迭代,还没真正从迭代拿出来数据
这台机器java只要大概4秒不到
0 请登录后投票
   发表时间:2011-03-18  
顿时觉得java hashmap写的挺强大了。。
是1亿次吗?
不过我还是觉得,还是输入时规范化成数组针对表达式计算性能更高。
0 请登录后投票
   发表时间:2011-03-18  
是1亿,没想到差距会这么大而且是c++慢10倍,现在手头没其他c++编译器和hash_map实现,还不能判断怎么回事
0 请登录后投票
   发表时间:2011-03-18  
可以尝试在c++中仿java写一个试试。。。相同的指令肯定c++更快。
0 请登录后投票
   发表时间:2011-03-18  
是debug版本的问题,换了release和优化op3,
执行大概6秒,加上->second把数据取出也差不多的时间
这台机器java取数大概花费14秒,这样时间算合理
同样的实现如果是指针实现变量读取,c++在1亿次下的累计要再估计
以前没比较过,没意识到debug和release速度会导致数量级的差别
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics