在看KMP算法时,想要简单的统计一下执行时间和性能。
得出的结论是: Java的String的indexOf方法性能最好,其次是KMP算法,其次是传统的BF算法,当然,对比有点牵强,SUN的算法也使用Java来实现、用的看着不像是KMP,还需要详细研究一下。
测试代码如下所示:
package com.test.test.kmp; import java.util.Random; public class KMPTest { public static void main(String[] args) { test(); } // public static void test() { // int allLen = 8000000; int subLen = 11; int charLen = 4; String cl = buildString(charLen); int times = 50; // testMatch(allLen, subLen, cl, times); } public static void testMatch(int allLen, int subLen, String cl, int times){ int allBF = 0; int allString = 0; int allKMP = 0; int allGC = 0; int allbuild = 0; int alltoArray = 0; long start = System.currentTimeMillis(); System.out.println("--------------------------"); for (int i = 0; i < times; i++) { // 1. 构造字符串的损耗 long buildStart = System.currentTimeMillis(); String sub = buildString(subLen, cl); String all = buildString(allLen, sub) +sub; long buildEnd = System.currentTimeMillis(); allbuild += (buildEnd - buildStart); // 2. toCharArray的损耗 long toArrayStart = System.currentTimeMillis(); char[] allArray = all.toCharArray(); char[] subArray = sub.toCharArray(); long toArrayEnd = System.currentTimeMillis(); alltoArray += (toArrayEnd - toArrayStart); // long startBF = System.currentTimeMillis(); int indexBF = bfIndexOf(all, sub); long endBF = System.currentTimeMillis(); // long timeoutBF = endBF - startBF; allBF += timeoutBF; System.gc(); allGC += (System.currentTimeMillis() - endBF); // long startString = System.currentTimeMillis(); int indexString = stringIndexOf(all, sub); long endString = System.currentTimeMillis(); // long timeoutString = endString - startString; allString += timeoutString; System.gc(); allGC += (System.currentTimeMillis() - endString); // long startKMP = System.currentTimeMillis(); //int indexKMP = kmpIndexOf(all, sub); int indexKMP = KMP_Index(allArray, subArray); long endKMP = System.currentTimeMillis(); // long timeoutKMP = endKMP - startKMP; allKMP += timeoutKMP; System.gc(); allGC += (System.currentTimeMillis() - endKMP); // //System.out.println("all="+all.substring(0,100)+" ......"); //System.out.println("sub="+sub); // //System.out.println("indexBF="+indexBF+";耗时: "+timeoutBF+"ms"); //System.out.println("indexString="+indexString+";耗时: "+timeoutString+"ms"); if(indexBF == indexString && indexKMP == indexString){ //System.out.println("!!!!对比相等。"); } else { throw new RuntimeException("对比出错."); } // if(i % 20 == 10){ System.out.println(i+"次bfIndexOf= "+allBF+"ms"); System.out.println(i+"次stringIndexOf= "+allString+"ms"); System.out.println(i+"次KMPIndexOf= "+allKMP+"ms"); System.out.println(i+"次allbuild= "+allbuild+"ms"); System.out.println(i+"次alltoArray= "+alltoArray+"ms"); System.out.println(i+"*3次,GC= "+allGC+"ms"); long end = System.currentTimeMillis(); long allTime = end-start; long lossTime = allTime - (allBF+allString+allKMP+allGC); System.out.println(i+"次,所有总计耗时: "+(allTime)+"ms; 损耗:" + lossTime +"ms; 损耗比: " +((0.0+lossTime)/allTime * 100)+"%"); System.out.println("--------------------------"); } } // System.out.println(times+"次bfIndexOf;总计耗时: "+allBF+"ms"); System.out.println(times+"次stringIndexOf;总计耗时: "+allString+"ms"); System.out.println(times+"次KMPIndexOf;总计耗时: "+allKMP+"ms"); System.out.println(times+"次allbuild= "+allbuild+"ms"); System.out.println(times+"次alltoArray= "+alltoArray+"ms"); System.out.println(times+"*3次,GC;总计耗时: "+allGC+"ms"); long end = System.currentTimeMillis(); long allTime = end-start; long lossTime = allTime - (allBF+allString+allKMP+allGC); System.out.println(times+"次,所有总计耗时: "+(allTime)+"ms; 损耗:" + lossTime +"ms; 损耗比: " +((0.0+lossTime)/allTime * 100)+"%"); System.out.println("--------------------------"); } // // 构建字符 public static String buildString(int len){ return buildString(len, null); } public static String buildString(int len, String sub){ // final int TYPE_NUMBER = 0; final int TYPE_LOWERCASE = 1; final int TYPE_UPPERCASE = 2; // long seed = System.nanoTime(); Random random = new Random(seed); // // StringBuilder builder = new StringBuilder(); for (int i = 0; i < len; i++) { // int type = random.nextInt(3);// 0-2 int cvalue = 0; if(TYPE_NUMBER == type){ cvalue = '0' + random.nextInt(10);// 0~(n-1) } else if(TYPE_LOWERCASE == type){ cvalue = 'a' + random.nextInt(26);// 0~(n-1) } else if(TYPE_UPPERCASE == type){ cvalue = 'A' + random.nextInt(26);// 0~(n-1) } else { throw new RuntimeException(Random.class.getName()+"#newxtInt(int);Wrong!"); } // //cvalue = 'A' + random.nextInt(26);// 0~(n-1) // char c = (char)cvalue; if(null != sub && sub.length() > 1){ int index = random.nextInt(sub.length()); c = sub.charAt(index); } //String s = String.valueOf(c); builder.append(c); // } // return builder.toString(); } /** * Java自带的方法,内部实现了 * @param all * @param sub * @return */ public static int stringIndexOf(String all, String sub){ // 防御式编程 if(null == all || null== sub){ return -1; } // 调用Java的String方法 return all.indexOf(sub); } /** * BF算法 * @param all * @param sub * @return */ public static int bfIndexOf(String all, String sub){ // 防御式编程 if(null == all || null== sub){ return -1; } // int lenAll = all.length(); int lenSub = sub.length(); int i = 0; while (i < lenAll) { // 从i下标开始对比 int j = 0; while (j < lenSub) { // char all_i = all.charAt(i); char sub_j = sub.charAt(j); if(all_i == sub_j){ // 相等则继续对比下一个字符 i++; j++; // 这个增长很重要 } else { // 否则跳出内层循环 break; } } // 如果 j 增长到和 lenSub相等,则匹配成功 if(lenSub == j){ return i - lenSub; } else { i = 1+i - j; // 回溯 i } } // return -1; } /** * KMP 算法 * @param all * @param sub * @return */ public static int kmpIndexOf(String all, String sub){ // char[] allArray = all.toCharArray(); char[] subArray = sub.toCharArray(); // return KMP_Index(allArray, subArray); } /** * 获得字符串的next函数值 * * @param t * 字符串 * @return next函数值 */ public static int[] next(char[] t) { int[] next = new int[t.length]; next[0] = -1; int i = 0; int j = -1; while (i < t.length - 1) { if (j == -1 || t[i] == t[j]) { i++; j++; if (t[i] != t[j]) { next[i] = j; } else { next[i] = next[j]; } } else { j = next[j]; } } return next; } /** * KMP匹配字符串 * * @param allArray * 主串 * @param subArray * 模式串 * @return 若匹配成功,返回下标,否则返回-1 */ public static int KMP_Index(char[] allArray, char[] subArray) { int[] next = next(subArray); int i = 0; int j = 0; while (i <= allArray.length - 1 && j <= subArray.length - 1) { if (j == -1 || allArray[i] == subArray[j]) { i++; j++; } else { j = next[j]; } } if (j < subArray.length) { return -1; } else return i - subArray.length; // 返回模式串在主串中的头下标 } }
测试的一个结果如下所示:
-------------------------- 10次bfIndexOf= 94ms 10次stringIndexOf= 56ms 10次KMPIndexOf= 76ms 10次allbuild= 5870ms 10次alltoArray= 137ms 10*3次,GC= 155ms 10次,所有总计耗时: 6388ms; 损耗:6007ms; 损耗比: 94.03569192235442% -------------------------- 30次bfIndexOf= 365ms 30次stringIndexOf= 222ms 30次KMPIndexOf= 295ms 30次allbuild= 16452ms 30次alltoArray= 395ms 30*3次,GC= 452ms 30次,所有总计耗时: 18184ms; 损耗:16850ms; 损耗比: 92.66388033435987% -------------------------- 50次bfIndexOf;总计耗时: 550ms 50次stringIndexOf;总计耗时: 335ms 50次KMPIndexOf;总计耗时: 450ms 50次allbuild= 26501ms 50次alltoArray= 637ms 50*3次,GC;总计耗时: 734ms 50次,所有总计耗时: 29211ms; 损耗:27142ms; 损耗比: 92.91705179555647% --------------------------
从中可以看出来,使用StringBuilder构造字符串,800万*50次append大约消耗了26秒。换算下来每秒钟是1600万次。。。
看来是需要写一个专门计时的函数,本来Junit是有自己的统计的,但是样本不太好做。
如此看来,数据的准备,也就是测试用例的选取很关键,可能需要先生成并写入到文本文件中。
我正在使用设置为log level=INFO的wildfly21。在部署的代码中有许多记录器。调试语句。 例如 调试语句没有正确记录到文件中,因为日志记录级别设置为INFO。 我的问题是关于logger的性能成本。调试。 在代码中保留调试语句是否有任何性能代价。或者是文件I/O中的实际成本,因此,在需要时将调试语句留作故障排除之用并无害处。
本文向大家介绍Java中Map的遍历方法及性能测试,包括了Java中Map的遍历方法及性能测试的使用技巧和注意事项,需要的朋友参考一下 1. 阐述 对于Java中Map的遍历方式,很多文章都推荐使用entrySet,认为其比keySet的效率高很多。理由是:entrySet方法一次拿到所有key和value的集合;而keySet拿到的只是key的集合,针对每个key,都要去Map中额外查找一次va
本文向大家介绍Java中的StringBuilder类的方法。,包括了Java中的StringBuilder类的方法。的使用技巧和注意事项,需要的朋友参考一下 以下是StringBuilder类提供的各种构造函数。 SN 构造函数与说明 1 StringBuilder() 构造一个不包含任何字符且初始容量为16个字符的字符串生成器。 2 StringBuilder(CharSequence seq
问题内容: 输出是 只是对.equals有一个简单的问题。 不管对象内容如何,仅当两个对象引用都指向同一对象时才返回true吗? 编辑 :现在我了解有关的部分,但是为什么2号线和3号线也不会返回? 编辑 :我相信看参考变量的地址,因此s1和s2不能相等。如果我的假设不正确,请纠正我 问题答案: 是,,这意味着两个对象引用不同,结果为false。 对于,您可以使用 为了进行编辑,您要在两个不同的St
本文向大家介绍java中stringBuilder的用法详解,包括了java中stringBuilder的用法详解的使用技巧和注意事项,需要的朋友参考一下 String对象是不可改变的。每次使用System.String类中的方法之一时,都要在内存中创建一个新的字符串对象,这就需要为该新对象分配新的空间。在需要对字符串执行重复修改的情况下,与创建新的String对象相关的系统开销可能会非常昂贵。如
性能测试应该有两个方向: 单接口压力测试 生产环境模拟用户操作高压力测试 生产环境模拟测试,目前我们都是交给公司的 QA 团队专门完成的。这块我只能粗略列举一下: 获取 1000 用户以上生产用户的访问日志(统计学要求 1000 是最小集合) 计算指定时间内(例如 10 分钟),所有接口的触发频率 使用测试工具(loadrunner, jmeter 等)模拟用户请求接口 适当放大压力,就可以模拟