在多线程应用程序中使用Random的正确方法

Ars*_*ray 43 c# random

好.以下是我所知道的不起作用:

int Rand()
{
    //will return the same number over and over again
    return new Random().Next();
}

static Random rnd=new Random();

int Rand()
{
    //if used like this from multiple threads, rnd will dissintegrate 
    //over time and always return 0
    return rnd.Next();
}
Run Code Online (Sandbox Code Playgroud)

这将正常工作,但如果由多个线程使用,CPU使用率上升,我不想要,我认为没有必要:

int Rand()
{
    lock(rnd)
    {
        return rnd.Next();
    }
}
Run Code Online (Sandbox Code Playgroud)

那么,c#是否有一个线程安全的Random类,或者更好的方法来使用它?

Ale*_*ria 64

我使用这样的东西:

public static class StaticRandom
{
    static int seed = Environment.TickCount;

    static readonly ThreadLocal<Random> random =
        new ThreadLocal<Random>(() => new Random(Interlocked.Increment(ref seed)));

    public static int Rand()
    {
        return random.Value.Next();
    }
}
Run Code Online (Sandbox Code Playgroud)

  • "随机"类从来就不是为了不可预测性而设计的.对于安全随机数,您需要来自`System.Security.Cryptography`的`RandomNumberGenerator`. (11认同)
  • @EricJ.不,因为它使用递增种子. (6认同)
  • 当创建线程并大约在同一时间开始使用它时,这是否会冒产生一堆具有相同种子的随机实例的风险? (3认同)
  • 我错过了增量。尽管如此,这仍会受到可预测性的影响。第一个种子基于滴答计数,因此可以猜测所有后续种子。Netscape 的 SSL 实现的早期版本由于基于时间戳的随机值而被破坏。如果没有硬件熵生成器,真正的不可预测性就非常重要。 (2认同)

Ben*_*hon 12

readonly ThreadLocal<Random> random = 
    new ThreadLocal<Random>(() => new Random(GetSeed()));

int Rand()
{
    return random.Value.Next();
}

static int GetSeed()
{
    return Environment.TickCount * Thread.CurrentThread.ManagedThreadId;
}
Run Code Online (Sandbox Code Playgroud)

(从Jeroen Vannevel的评论中无耻地偷走了)

  • 改善建议没有羞耻感!;) (2认同)
  • 将时间与线程ID相乘是愚蠢的.考虑其中一个是0,或者甚至只是两个幂的情况.即使这不是一个问题,为每个实例生成一个随机的31位种子会让你比Alessandro更难以解决生日问题. (2认同)

Bat*_*via 5

我想你想要的是线程

[ThreadStatic]
static Random rnd=new Random();

int Rand()
{
    if ( rnd == null ) 
    {
       rnd = new Random()
    }
    //Now each thread gets it's own version
    return rnd.Next();
}
Run Code Online (Sandbox Code Playgroud)

这样每个线程都可以获得自己的rnd属性版本

你的锁定会增加cpu使用率的原因是因为所有线程都会等待那一点(如果你经常使用它应该只是一个问题)

[更新]我修复了初始化.正如有人指出的那样,它确实留下了这样一个事实,即如果你在相同的毫秒内启动多个线程,那么它们将产生相同的结果.

  • 根据这个答案http://stackoverflow.com/a/18337158/1164966,`ThreadLocal <T>`优先于`[ThreadStatic]`,因为它保证为每个线程初始化该字段. (4认同)
  • 无论如何,这都是冒险的.如果你快速连续开始两个线程,他们的种子可以是相同的. (3认同)