您的位置:首页 > 其它

【性能】甲 Spads 出品字符串高效提取数值方法 Shane 末日圣诞奉献 推荐

2012-12-26 04:55 851 查看
Spads 出品,作者 WangXP 与 Shane

目录

---------- ---------- ---------- ----------

1 【综述】 http://shanelooli.blog.51cto.com/5523233/1100063

2 【程序】 http://shanelooli.blog.51cto.com/5523233/1100074

3 【功能】 http://shanelooli.blog.51cto.com/5523233/1100356

4 【性能】 测试程序 http://shanelooli.blog.51cto.com/5523233/1100417

_      测试分析 http://shanelooli.blog.51cto.com/5523233/1100418

5 【附录】

因为篇幅原因,51CTO 只允许单篇 80000 个字符,所以本文将拆分成几个部分发布。

其中 5【附录】是针对 1【综述】内容的,所以放在了一起。

4 【性能】

---------- ---------- ---------- ----------

根据功能测试,我们可以看到,各种简易方法都不能满足需要。接下来对几种能够满足需要的“完整”方法来进行性能测评对比。测试程序通过多线程,每个线程执行一种方案若干次,来直观地表现各种方法的快慢。这种测试被重复了七轮,基本消除了线程调度起伏带来的影响。每轮执行的时间都收录并累加,作为最终评判各方法性能的依据。线程控制使用了原子操作类。测试代码如下。

public void testFetchNumberPerformance()
{
Runnable r;
List<SortedMap<Long, String>> timeUsed =
new ArrayList<SortedMap<Long, String>>(this.numStrs.length);
System.out.println("Loop times = " + this.loopNum);
System.out.println("---------- ---------- ---------- ----------");
for (final String numStr: this.numStrs)
{
final Map<String, Long> timeUsedCount =
Collections.synchronizedMap(new HashMap<String, Long>());

System.out.println("String: " + numStr);

for (int loop = -1; ++loop != 7; )
{
final AtomicInteger runThreadNum = new AtomicInteger(0);

// StringTool
r = new Runnable()
{
public void run()
{
boolean hasEx = false;
if (timeUsedCount.get("StringTool") == null)
timeUsedCount.put("StringTool", 0L);
long start = System.currentTimeMillis();
for (int index = -1; ++index != FetchNumberTest.this.loopNum; )
{
try { StringTool.parseNumber(numStr); }
catch (Exception ex) { hasEx = true; }
}
long use = System.currentTimeMillis() - start;
System.out.print("\ttool:" + use + "ms" + (hasEx ? "(EX)" : "") + '.');
use += timeUsedCount.get("StringTool");
timeUsedCount.put("StringTool", use);
runThreadNum.addAndGet(-1);
Thread.yield();
}
};
runThreadNum.addAndGet(1);
new Thread(r).start();

// JavaLib
r = new Runnable()
{
public void run()
{
boolean hasEx = false;
if (timeUsedCount.get("JavaLib") == null)
timeUsedCount.put("JavaLib", 0L);
long start = System.currentTimeMillis();
for (int index = -1; ++index != FetchNumberTest.this.loopNum; )
{
try { FetchNumberTest.this.fetchNumberByJavaLib(numStr); }
catch (Exception ex) { hasEx = true; }
}
long use = System.currentTimeMillis() - start;
System.out.print("\tlib:" + use + "ms" + (hasEx ? "(EX)" : "") + '.');
use += timeUsedCount.get("JavaLib");
timeUsedCount.put("JavaLib", use);
runThreadNum.addAndGet(-1);
Thread.yield();
}
};
runThreadNum.addAndGet(1);
new Thread(r).start();

// WholeRegex
r = new Runnable()
{
public void run()
{
boolean hasEx = false;
if (timeUsedCount.get("WholeRegex") == null)
timeUsedCount.put("WholeRegex", 0L);
long start = System.currentTimeMillis();
for (int index = -1; ++index != FetchNumberTest.this.loopNum; )
{
try { FetchNumberTest.this.fetchNumberByRegex(numStr, false); }
catch (Exception ex) { hasEx = true; }
}
long use = System.currentTimeMillis() - start;
System.out.print("\treg:" + use + "ms" + (hasEx ? "(EX)" : "") + '.');
use += timeUsedCount.get("WholeRegex");
timeUsedCount.put("WholeRegex", use);
runThreadNum.addAndGet(-1);
Thread.yield();
}
};
runThreadNum.addAndGet(1);
new Thread(r).start();

// Direct
r = new Runnable()
{
public void run()
{
boolean hasEx = false;
if (timeUsedCount.get("Direct") == null)
timeUsedCount.put("Direct", 0L);
long start = System.currentTimeMillis();
for (int index = -1; ++index != FetchNumberTest.this.loopNum; )
{
try { FetchNumberTest.this.fetchNumberByDirect(numStr); }
catch (Exception ex) { hasEx = true; }
}
long use = System.currentTimeMillis() - start;
System.out.print("\t--:" + use + "ms" + (hasEx ? "(EX)" : "") + '.');
use += timeUsedCount.get("Direct");
timeUsedCount.put("Direct", use);
runThreadNum.addAndGet(-1);
Thread.yield();
}
};
runThreadNum.addAndGet(1);
new Thread(r).start();

// WholeApacheUtils
r = new Runnable()
{
public void run()
{
boolean hasEx = false;
if (timeUsedCount.get("WholeApacheUtils") == null)
timeUsedCount.put("WholeApacheUtils", 0L);
long start = System.currentTimeMillis();
for (int index = -1; ++index != FetchNumberTest.this.loopNum; )
{
try { FetchNumberTest.this.fetchNumberByApacheUtils(numStr); }
catch (Exception ex) { hasEx = true; }
}
long use = System.currentTimeMillis() - start;
System.out.print("\tap:" + use + "ms" + (hasEx ? "(EX)" : "") + '.');
use += timeUsedCount.get("WholeApacheUtils");
timeUsedCount.put("WholeApacheUtils", use);
runThreadNum.addAndGet(-1);
Thread.yield();
}
};
runThreadNum.addAndGet(1);
new Thread(r).start();

while (runThreadNum.get() != 0)
{
try { Thread.sleep(10); } catch (Exception ex) { }
Thread.yield();
}

for (int index = -1; ++index != 3; )
{
try { Thread.sleep(100); } catch (Exception ex) { }
Thread.yield();
}
System.out.println();
}

SortedMap<Long, String> thisNumStrTimeUsed =
Collections.synchronizedSortedMap(new TreeMap<Long, String>());
for (String name: timeUsedCount.keySet())
thisNumStrTimeUsed.put(timeUsedCount.get(name), name);
timeUsed.add(thisNumStrTimeUsed);

for (Long time: thisNumStrTimeUsed.keySet())
System.out.println(thisNumStrTimeUsed.get(time) + ": " + time + " ms.");

System.out.println("---------- ---------- ---------- ----------");
}
}


┌────────────┐

│ 以下是51CTO独家 │

└────────────┘

我们可以看到,在这个测试程序,我为每一种方案开启了一个线程。当这个线程完毕之后,就会报告这种方法的用时。基于这种设计,能够方便地让先执行完的线程将时间先输出出来。为了输出格式考虑,每一轮测试,每一种方案我都是用 System.out.print(String) 方法来进行输出的。那么就需要在最后一个线程执行结束之后输出一个回车符。我在主线程中采取了人工阻塞的方式,通过线程跳过和睡眠,让主线程等待所有测试线程执行完毕。

为了防止测试线程没有执行完毕主线程就输出回车符,我进行了一种控制,通过 final AtomicInteger runThreadNum 进行线程计数。使用 final 的变量,会尽可能地使用 CPU 二级缓存。然后因为线程在生成之前就进行了线程计数 +1 ,所以只可能发生线程没有成功启动于是计数没有回归的情况,不可能发生漏计数回车符提前输出的情况。AtomicInteger 提供了很多利用 CPU 指令单步操作的方法,可以避开多线程操作同一个数据有可能产生的并发问题。

本文还发表在我的其它技术日志

CSDN : http://blog.csdn.net/shanelooli/article/details/8432250

ITeye : http://surmounting.iteye.com/blog/1754323

中国开源社区: http://my.oschina.net/shane1984/blog/98088
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息