在Web服务器上,许多线程正在向客户端提供内容。 A / B测试在网站上进行,因此我们需要PRNG为每个会话和测试选择一个变体。 显然,当使用PRNG的单个实例时,它会被同时访问,因此可能需要适当的锁定或其他机制。
最初我们使用了java.util.Random
(juR),但由于它有提到的缺陷,例如How good is java.util.Random,我们尝试使用MersenneTwister。
但是,由于Mersenne-Twister relies on an internal state这一事实导致性能大幅下降,因此需要同步访问nextInt()
。
另一种选择可能是XOR换档PRNG,但它与Mersenne Twister有同样的问题。
您可以找到解释,例如在这里:http://xorshift.di.unimi.it/
Random
uses a compareAndSet操作,由于它不需要锁定,因此似乎要快得多,但根据类Javadoc,它仍然不是线程安全的。相反,建议使用ThreadLocalRandom
代替,这基本上会产生一个PRNG池。根据请求,随机可用线程处理HTTPS请求,因此从一组可用PRNG中选择随机PRNG。显然这很快。
来自这样一个池的随机数是否与单个PRNG实例中的随机数一样好?
另一种方法是使用单个PRNG实例从其预先生成值流,例如使用ArrayBlockingQueue
。
哪种解决方案在性能方面更有效?
答案 0 :(得分:3)
您可以通过BlockingQueue
。
class SafeRandom implements Runnable {
Random r = new Random();
BlockingQueue<Double> q = new ArrayBlockingQueue<>(10);
double get() throws InterruptedException {
return q.take();
}
@Override
public void run() {
try {
while (true) {
q.put(r.nextDouble());
}
} catch (InterruptedException ie) {
}
}
}
答案 1 :(得分:2)
为避免同步问题,每个线程都有一个RNG。为了避免线程特定的RNG给出相同的输出,让主RNG为线程特定的RNG生成一系列初始种子。这可能需要将额外的种子参数传递到您的代码中以生成新线程。
您需要自己测试一下RNG的不同选项在您的工具包上的运行速度。如果需要,可以将不同的RNG引擎用于主RNG和线程特定的RNG。通常选择具有线程特定RNG的快速建立时间的RNG。这对主RNG来说并不重要,因为它只设置一次。