在web服务器上,许多线程向客户端提供内容。A/B测试是在网站上执行的,因此我们需要一个PRNG来为每个会话和测试选择一个变体。显然,当使用PRNG的单个实例时,它是并发访问的,因此可能需要适当的锁定或其他机制。
最初我们使用java.util.Random(juR),但是由于它有提到的缺陷,例如java.util.Random有多好?,所以我们尝试使用MersenneTwister。然而,由于Mersenne-Twister 依赖于内部状态的事实,我们看到了性能的大幅下降,因此它对nextInt()的访问需要同步。另一种选择可能是XOR shift PRNG,但它与Mersenne Twister有相同的问题。你可以在这里找到解释,例如:http://xorshift.di.unimi.it/
Random 使用compareAndSet操作看起来要快得多,因为它不需要锁定,但是根据Javadoc类,它仍然不安全。相反,建议使用ThreadLocalRandom,这基本上会导致一个PRNG池,当请求时,一个随机可用线程处理HTTPS请求,因此从一组可用的PRNG中选择一个随机的PRNG,显然这是相当快的。
从这样一个池中产生的随机数是否与来自单个PRNG实例的随机数一样好?
另一种方法是使用单个PRNG实例预生成一个值流,例如使用ArrayBlockingQueue。
哪种解决方案在性能方面会更好呢?
发布于 2016-01-04 13:13:41
通过通过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) {
}
}
}发布于 2016-01-02 16:26:00
为了避免同步问题,每个线程有一个RNG。为了避免线程特定的RNGs提供相同的输出,让主RNG为线程特定的RNGs生成一系列初始种子。这可能需要一个额外的种子参数传递到您的代码中,以生成一个新线程。
您需要自己测试RNG在您的工具包上运行的速度有多快。如果需要,可以为主RNG和特定于线程的RNG使用不同的RNG引擎。通常,为线程特定的RNG选择具有快速设置时间的RNG。这对主RNG没有那么重要,因为它只设置了一次。
https://stackoverflow.com/questions/34567378
复制相似问题