锁定老帖子 主题:FEL(表达式语言)——7月30号更新
精华帖 (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); } } |
|
返回顶楼 | |
发表时间:2011-03-17
ppgunjack 写道 原来写这个的时候公司已经用一个叫jbell的库做了实现,但我感觉性能不好,所以自己用的时候重写了实现,做的时候就是尽量规避两个事情:继承,字符串处理
在做计算的时候,尽量都用switch和数字比较来处理逻辑,但对变量这个问题一直想不出合适方案,总会在某个地方引入循环内调用的字符串函数 动态编译的东西如果没有继承或者接口,就只能通过反射调用,这种情况更慢,这也是动态编译的一个硬伤。 事实证明,invokespecial要比invokevirtual和invokeinterface快多了。但是真的没办法- - |
|
返回顶楼 | |
发表时间:2011-03-17
很有启发性,如果可以扩展String加个唯一id作为成员,再加上个全局id生成器那事情就简单多了,台面用字符串,台下用数字,也不用每次算hash
|
|
返回顶楼 | |
发表时间: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再试试 |
|
返回顶楼 | |
发表时间:2011-03-18
你算的是取出的时间吗?。。
|
|
返回顶楼 | |
发表时间:2011-03-18
对,只算取出时间,而且只是运行到返回迭代,还没真正从迭代拿出来数据
这台机器java只要大概4秒不到 |
|
返回顶楼 | |
发表时间:2011-03-18
顿时觉得java hashmap写的挺强大了。。
是1亿次吗? 不过我还是觉得,还是输入时规范化成数组针对表达式计算性能更高。 |
|
返回顶楼 | |
发表时间:2011-03-18
是1亿,没想到差距会这么大而且是c++慢10倍,现在手头没其他c++编译器和hash_map实现,还不能判断怎么回事
|
|
返回顶楼 | |
发表时间:2011-03-18
可以尝试在c++中仿java写一个试试。。。相同的指令肯定c++更快。
|
|
返回顶楼 | |
发表时间:2011-03-18
是debug版本的问题,换了release和优化op3,
执行大概6秒,加上->second把数据取出也差不多的时间 这台机器java取数大概花费14秒,这样时间算合理 同样的实现如果是指针实现变量读取,c++在1亿次下的累计要再估计 以前没比较过,没意识到debug和release速度会导致数量级的差别 |
|
返回顶楼 | |