以下是Skeet posting for a random provider:
的高潮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;
}
}
我想在.NET 3.5项目中使用相同的概念,因此ThreadLocal不是一个选项。
如果没有ThreadLocal的帮助,您如何修改代码以获得线程安全的随机提供程序?
好的,我现在和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))); }
}
答案 0 :(得分:9)
如果没有ThreadLocal的帮助,您如何修改代码以获得线程安全的随机提供程序?
Jon在您关联的文章中回答了您的问题:
使用一个实例,但也使用每个调用者在使用随机数生成器时必须记住获取的锁。这可以通过使用为您执行锁定的包装器来简化,但在多线程系统中,您仍然可能浪费大量时间等待锁定。
所以每次在包装器中锁定它,并在完成后解锁它。
如果这个足够便宜,很好,它足够便宜。
如果那不够便宜,那么你有两个选择。首先,使它更便宜。其次,编写一个伪随机数生成器的线程安全实现,可以在不锁定的情况下使用。
有很多方法可以降低它的价格。例如,你可以换空间时间;你可以在程序启动时生成一个十万个随机数的数组,然后编写一个无锁算法,从数组中提供先前计算的随机值。当您用完值时,在数组中生成另外十万个值,并将旧数组换成旧数组。
它的缺点是它的内存消耗量大约是它的十万倍,并且每十万个数字突然变得非常慢,然后再次加速。如果这是不可接受的,那么会提出一个可接受的策略。你是那个知道什么是可接受的表现而不是什么的人。
或者,就像我说的那样,如果你不喜欢为你提供的那个,请自己写。使用可接受的性能编写Random的线程安全实现,并从多个线程中使用它。
我看到了Jon所说的关于锁定包装器的内容,但不确定代码的样子!
类似的东西:
sealed class SafeRandom
{
private Random random = new Random();
public int Next()
{
lock(random)
{
return random.Next();
}
}
}
现在每次拨打“下一步”时,都会锁定。 (总是锁定私有对象;这样你知道你的代码是锁定它的唯一代码!)如果两个线程同时调用Next,那么“失败者”阻止,直到“胜利者”离开下一个方法。
如果您愿意,甚至可以将SafeRandom对象设为静态类:
static class SafeRandom
{
private static Random random = new Random();
public static int Next()
{
lock(random)
{
return random.Next();
}
}
}
现在您可以从任何线程调用SafeRandom.Next()。
答案 1 :(得分:8)
[ThreadStatic]
private static Random _random;
private static Random Random
{
get
{
int seed = Environment.TickCount;
return _random ?? (_random = new Random(Interlocked.Increment(ref seed)))
}
}
答案 2 :(得分:1)
我刚刚阅读了“C#in Depth”的链接,虽然我同意Random不是线程安全的事实是一种痛苦,但实际上我会使用不同的方法来解决问题,即出于性能原因。
实例化一个随机引擎是一个非常繁重的动作,所以我宁愿只保留一个实例,并通过使用锁来保证线程安全:
public static class RandomProvider
{
private static Random randomEngine = new Random(Environment.TickCount);
private static object randomLock = new object();
public static int GetRandomValue()
{
lock(randomLock)
{
return randomEngine.Next();
}
}
}
HTH