.NET中的随机和线程问题

时间:2009-10-07 14:38:08

标签: c# .net multithreading data-structures collections

我在使用.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)

3 个答案:

答案 0 :(得分:4)

尝试lock Random对象。

int RandomLevel()
{
    int height = 1;

    lock(rnd)
    {
        while(rnd.NextDouble >= 0.5 && height < MaxHeight) height++;
    }

    return height;
}

当多个线程同时访问Random对象时,可能存在冲突问题,并且种子可能已损坏。我无法深入了解可能具体发生的事情,但根据MSDNRandom类型的实例成员不保证是线程安全的,所以似乎在任何情况下都需要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对象,它可能会返回一个可预测的数字流,而不是真正随机的数字流。也许不会导致你在这里看到的行为,但需要考虑前进。