在.Net 3.5中实现随机提供程序

Ber*_*ryl 8 .net c# random .net-3.5

以下是随机提供商Skeet帖子的高潮:

public static class RandomProvider
{    
    private static int seed = Environment.TickCount;

    private static ThreadLocal<Random> randomWrapper = new ThreadLocal<Random>(() =>
        new Random(Interlocked.Increment(ref seed))
    );

    public static Random GetThreadRandom()
    {
        return randomWrapper.Value;
    }
}
Run Code Online (Sandbox Code Playgroud)

我想在.NET 3.5项目中使用相同的概念,因此ThreadLocal不是一个选项.

如果没有ThreadLocal的帮助,你如何修改代码以拥有一个线程安全的随机提供程序?

UPDATE

好的,我现在和Simon的[ThreadStatic]一起去,因为我最了解它.这里有很多好的信息可以随着时间的推移进行审核和重新思考.谢谢大家!

public static class RandomProvider
{
    private static int _seed = Environment.TickCount;

    [ThreadStatic]
    private static Random _random;

    /// <summary>
    /// Gets the thread safe random.
    /// </summary>
    /// <returns></returns>
    public static Random GetThreadRandom() { return _random ?? (_random = new Random(Interlocked.Increment(ref _seed))); }
}
Run Code Online (Sandbox Code Playgroud)

Eri*_*ert 9

如果没有ThreadLocal的帮助,你如何修改代码以拥有一个线程安全的随机提供程序?

Jon在您链接的文章中回答了您的问题:

使用一个实例,但也使用一个锁,每个调用者在使用随机数生成器时必须记住这个锁.这可以通过使用为您执行锁定的包装器来简化,但在多线程系统中,您仍然可能浪费大量时间等待锁定.

所以每次在包装器中锁定它,并在完成后解锁它.

如果它足够便宜,很好,它足够便宜.

如果这不够便宜,那么你有两个选择.首先,让它更便宜.其次,编写一个伪随机数生成器的线程安全实现,可以在不锁定的情况下使用.

有很多方法可以降低它的价格.例如,你可以换空间时间; 你可以在程序启动时生成一个十万个随机数的数组,然后编写一个无锁算法,从数组中提供先前计算的随机值.当您用完值时,在数组中生成另外十万个值,并将旧数组换成旧数组.

这有一个缺点,它的内存消耗大约是它的十万倍,并且每十万个数字突然变得非常慢,然后再次加速.如果这是不可接受的,那么提出一个可以接受的策略.你是那个知道什么是可接受的表现而不是什么的人.

或者,就像我说的那样,如果你不喜欢为你提供的那个,那就写下你自己的.使用可接受的性能编写Random的线程安全实现,并从多个线程中使用它.

我看到了Jon所说的关于锁定包装器的内容,但不确定代码的样子!

就像是:

sealed class SafeRandom
{
    private Random random = new Random();
    public int Next()
    {
        lock(random)
        {
            return random.Next();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

现在,每当你打电话给Next时,你都会锁定.(总是锁定一个私有对象 ;这样你知道你的代码是锁定它的唯一代码!)如果两个线程同时调用Next,那么"loser"会阻塞,直到"winner"离开Next方法.

如果您愿意,您甚至可以将SafeRandom对象设为静态类:

static class SafeRandom
{
    private static Random random = new Random();
    public static int Next()
    {
        lock(random)
        {
            return random.Next();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

现在你可以从任何线程调用SafeRandom.Next().


Ter*_*kel 8

您可以使用ThreadStaticAttribute

[ThreadStatic]
private static Random _random;

private static Random Random
{
    get
    {
        int seed = Environment.TickCount;

        return _random ?? (_random = new Random(Interlocked.Increment(ref seed)))
    }
}
Run Code Online (Sandbox Code Playgroud)