Quelqu'un peut-il me dire si la méthode C # Random.Next () est thread-safe?
Réponses
Trop de publicités?Non, l'utilisation de la même instance à partir de plusieurs threads peuvent provoquer la rupture et le retour de tous les 0. Cependant, la création d'une version thread-safe (sans avoir besoin de méchant verrous sur chaque appel d' Next()
) est simple. Adapté à partir de l'idée dans cet article:
public class ThreadSafeRandom
{
private static readonly Random _global = new Random();
[ThreadStatic] private static Random _local;
public ThreadSafeRandom()
{
if (_local == null)
{
int seed;
lock (_global)
{
seed = _global.Next();
}
_local = new Random(seed);
}
}
public int Next()
{
return _local.Next();
}
}
L'idée est de garder un static Random
variable pour chaque thread. Le moyen évident échoue, cependant, en raison d'un autre problème avec l' Random
- si plusieurs instances sont créées à peu près au même moment (dans les 15ms), ils seront tous de retour les mêmes valeurs! Pour résoudre ce problème, nous créons un monde statique Random
exemple pour générer les graines utilisées par chaque thread.
L'article ci-dessus, par la manière, le code de preuve à la fois de ces questions avec Random
.
La réponse officielle de Microsoft est une très forte pas:
http://msdn.microsoft.com/en-us/library/system.random.aspx#8
Il y a un très vilain effet secondaire qui peut se produire lorsque le même objet Aléatoire est utilisé par plusieurs threads: il s'arrête juste au travail
(c'est une condition de concurrence qui, lorsqu'il est déclenché, la valeur de retour de l '" aléatoire.Prochaine....' des méthodes de 0 (pour tous les appels ultérieurs))
Une autre façon de traiter les threads consiste à utiliser ThreadLocal<T>
comme suit:
new ThreadLocal<Random>(() => new Random(GenerateSeed()));
La méthode GenerateSeed()
devra renvoyer une valeur unique à chaque appel afin de garantir que les séquences de nombres aléatoires sont uniques dans chaque thread.
static int SeedCount = 0;
static int GenerateSeed() {
return (int) ((DateTime.Now.Ticks << 4) +
(Interlocked.Increment(ref SeedCount)));
}
Travaillera pour un petit nombre de threads.