我有一个基于Web的Java应用程序,它为会话信息生成随机UUID.我们的一位测试人员根据他自己的分析声称最多可以生成350毫秒来生成UUID,但我还没有能够复制他的结果.他指出这篇文章http://www.cowtowncoder.com/blog/archives/2010/10/entry_429.html来帮助支持他的结果.我想看看是否有其他人在Java 6或Java 7应用程序中使用Java的内置UUID生成功能遇到了这个限制.
Bas*_*que 19
请记住,这个测试是不现实的,超出了我能想象的最坏情况.我的目标是安静那些在没有事实的情况下对UUID进行恶意使用的人来支持他们的批评.
场景:
java.util.UUID.randomUUID()
在一个线程中运行一个循环,因此不会对同步的方法/类进行争用.
// Warm the random generator.
java.util.UUID uuid;
uuid = java.util.UUID.randomUUID();
long stop = 0;
long start = System.nanoTime();
int loops = 1000000; // One million.
for ( int i = 0; i < loops; i++ ) {
uuid = java.util.UUID.randomUUID();
}
stop = System.nanoTime();
long elapsed = ( stop - start );
System.out.println( "UUIDs: " + loops );
System.out.println( "Nanos: " + elapsed );
System.out.println( "Nanos per uuid: " + ( elapsed / loops ) + " ( micros per: " + ( elapsed / loops / 1000 ) + " )" );
Run Code Online (Sandbox Code Playgroud)
每个UUID 约2微秒.
与上面类似,但在进行一百万次调用的循环时,我们还有两个其他线程在运行,每个线程都有一千万次调用.
// Warm the random generator.
java.util.UUID uuid;
uuid = java.util.UUID.randomUUID();
int pass = 10_000_000 ; // Ten million.
MyThread t1 = new MyThread( pass );
MyThread t2 = new MyThread( pass );
t1.start();
t2.start();
t3.start();
long stop = 0;
long start = System.nanoTime();
int loops = 1_000_000 ; // One million.
for ( int i = 0; i < loops; i++ ) {
uuid = java.util.UUID.randomUUID();
}
stop = System.nanoTime();
long elapsed = ( stop - start );
System.out.println( "UUIDs: " + loops );
System.out.println( "Nanos: " + elapsed );
System.out.println( "Nanos per uuid: " + ( elapsed / loops ) + " ( micros per: " + ( elapsed / loops / 1000 ) + " )" );
Run Code Online (Sandbox Code Playgroud)
并且定义每个线程的类......
class MyThread extends Thread {
private int loops;
public MyThread( int loops ) {
this.loops = loops;
}
@Override
public void run() {
java.util.UUID uuid;
for ( int i = 0; i < this.loops; i++ ) {
uuid = java.util.UUID.randomUUID();
}
}
}
Run Code Online (Sandbox Code Playgroud)
每个UUID 约20微秒.
每个UUID运行14,20,20,23和24微秒(不按此顺序).所以在极端争用下只差了大约10倍,在我所知道的任何实际使用中都可以接受20微秒.
Ste*_*n C 12
随机形式的UUID需要"加密强度"随机数源.(如果没有那么可能会重新发出给定UUID的可能性会增加到令人担忧的水平.)
典型的加密随机数生成器使用应用程序外部的熵源.它可能是硬件随机数生成器,但更常见的是它是在正常操作中由操作系统收集的累积"随机性".问题是熵源具有速率限制.如果您在一段时间内超过该速率,则可以耗尽源.接下来发生的是系统相关的,但在某些系统上,读取熵的系统调用将停止......直到有更多可用.
我希望这是您客户的系统上发生的事情.
一种解决方法(对于Linux系统)是安装UUID守护程序并将其配置为使用伪随机数生成器"充值"熵池.缺点是这可能会损害您的UUID生成器的随机性.
我测试了它
for (;;) {
long t0 = System.currentTimeMillis();
for (int i = 0; i < 1000000; i++) {
UUID.randomUUID();
}
System.out.println(System.currentTimeMillis() - t0);
}
Run Code Online (Sandbox Code Playgroud)
在我的电脑上它是~1100毫秒,这是非常慢的.UUID.randomUUID()在内部使用SecureRandom,使其更快,我们可以使用常规的java.util.Random
Random r = new Random();
for (;;) {
..
new UUID(r.nextLong(), r.nextLong());
Run Code Online (Sandbox Code Playgroud)
它是~80毫秒
线程数对UUID生成的性能产生巨大影响.这可以通过查看其实现SecureRandom#nextBytes(byte[]生成随机数来解释UUID.randomUUID():
synchronized public void nextBytes(byte[] bytes) {
secureRandomSpi.engineNextBytes(bytes);
}
Run Code Online (Sandbox Code Playgroud)
nextBytes是synchronized时,由不同的线程访问导致显著的性能损失.
使用版本 1 类型的 UUID 怎么样?
\n\n版本 1基于MAC 地址和当前时间(“空间和时间”)。与版本 4 相比,发生冲突的可能性要小得多。
\n\n版本 4完全基于使用加密的强随机生成器从随机数生成。
\n\nOracle JVM 不提供版本 1 生成器,显然是出于安全和隐私方面的考虑。JVM 不提供对主机 MAC 地址的访问。
\n\n至少有一个第三方库可以提供版本 1 UUID 以及其他版本:JUG \xe2\x80\x93 Java UUID Generator。他们表示,Java 6 中引入的功能使他们能够访问 MAC 地址。
\n\n请阅读2010 年文章“更多关于 Java UUID 生成器 (JUG) ,谈性能”中关于使用Java UUID 生成器版本 3 的性能和测试结果的讨论。Tatu Saloranta 在他的 MacBook 上测试了各种 UUID。
\n\n结果:MAC+Time 版本比随机版本快 20 倍。
\n\n\n\n基于时间的变体(以太网地址加时间戳)要快得多,几乎是基于随机的默认变体的 20 倍,每秒生成约 500 万个 UUID。
\n
| 归档时间: |
|
| 查看次数: |
25664 次 |
| 最近记录: |