我在使用.NET中的Random类时遇到问题,我正在实现一个工作正常的线程集合,除了一个较小的细节。该集合是Skip list,熟悉它的人都知道,对于插入的每个节点,我需要生成一个<= CurrentMaxHeight+1
的新高度,这是我用来做这个的代码(I知道这是非常低效的,但它起作用,这是我现在的主要优先事项)
int randomLevel()
{
int height = 1;
while(rnd.NextDouble() >= 0.5 && height < MaxHeight)
++height;
return height;
}
我的问题在于,有时候我连续几千个元素只能从这里获得1个元素,这会杀死跳过列表的性能。 10.000个元素连续生成这个方法只有1个的机会,看起来非常渺茫(非常一致)。
所以我假设(猜测)以某种方式存在Random
对象的问题,但我真的不知道从哪里开始挖掘。所以我转向stackoverflow看看是否有人有想法?
修改
rnd-variable在类SkipList<T>
中声明,并且可以从多个线程访问(每个线程调用集合上的.Add和Add调用.randomLevel)
答案 0 :(得分:4)
尝试lock
Random
对象。
int RandomLevel()
{
int height = 1;
lock(rnd)
{
while(rnd.NextDouble >= 0.5 && height < MaxHeight) height++;
}
return height;
}
当多个线程同时访问Random
对象时,可能存在冲突问题,并且种子可能已损坏。我无法深入了解可能具体发生的事情,但根据MSDN,Random
类型的实例成员不保证是线程安全的,所以似乎在任何情况下都需要lock
。
答案 1 :(得分:3)
我不会锁定整个while循环。只需锁定rnd.NextDouble()调用。
int RandomLevel()
{
int height = 1;
double newRand;
lock(rnd) { newRand = rnd.NextDouble(); }
while(newRand >= 0.5 && height < MaxHeight)
{
height++;
lock(rnd) { newRand = rnd.NextDouble(); }
}
return height;
}
虽然如果考虑性能,我肯定会比较两种解决方案,因为单线程与多线程性能可能存在差异。
答案 2 :(得分:1)
看起来你的循环运行时间不到它所调用的时间的一半 - 是你正在寻找的东西(当0到1之间的随机数> 0.5时?这可以解释为什么你会得到“1 “比你预期的更频繁 - 至少有一半的时间,它甚至没有运行增加高度的循环 - 它只是将高度设置为1,不改变它,然后返回”1“。我不是熟悉跳过列表,所以这可能是有意的,但我想我会问。
我对使用随机数不太熟悉,但是你有可能出现播种问题吗?如果你在实例化它时没有随机化Random对象,它可能会返回一个可预测的数字流,而不是真正随机的数字流。也许不会导致你在这里看到的行为,但需要考虑前进。