2009-07-06 8 views
3

Je ne demande pas si ceux-ci sont vraiment aléatoires. Je voulais juste savoir si deux utilisateurs frappent la même page en même temps peuvent-ils obtenir le même nombre aléatoire? Je pense que si je cours ceci sur un serveur multicore je générerai le même nombre de randon une bonne quantité de temps dû à la synchronisation ou à d'autres raisons?Ces numéros aléatoires sont-ils 'sûrs'

public static class SBackend 
{ 
    static Random randObj = null; 
    public static void init() 
    { 
     randObj = new Random((int)DateTime.Now.ToBinary()); 
     runFirstTime(); 
    } 

    public static long getRandomId() 
    { 
     long randNum = (long)randObj.Next() << 33; 
     randNum |= (uint)randObj.Next() << 2; 
     randNum |= (uint)randObj.Next() & 3; 
     return randNum; 
    } 
} 
+0

Salut AcidZombie, pourquoi avez-vous besoin de garantir que deux personnes n'obtiennent pas le même nombre aléatoire? Quel est le problème sous-jacent que vous essayez de résoudre? Etes-vous également dans ASP.Net?(comme vous référez aux pages dans votre question) –

+0

Je l'employais pour deux choses mais je réalise que je peux employer une valeur linéaire pour l'un des. J'utilise actuellement ceci pour produire un Id de logid. L'utilisateur a un cookie avec le nom d'utilisateur et un httpcookie avec le loginId. Si quelqu'un peut deviner un identifiant de connexion spécifique à un utilisateur, il peut se connecter comme lui. Notez que ceci change chaque fois que l'utilisateur se connecte et met à 0 lors de la déconnexion –

Répondre

7

Oui, il est possible que cela génère les mêmes nombres. La graine n'ajoute rien (c'est le temps par défaut de toute façon).

également - si elle est statique, vous devez synchronisez (Next est thread-safe):

static readonly Random rand = new Random(); 
public static int NextInt32() { 
    lock(rand) { return rand.Next();} 
} 
public static long NextInt64() { 
    lock(rand) { // using your algorithm... 
     long randNum = (long)rand.Next() << 33; 
     randNum |= (uint)rand.Next() << 2; 
     randNum |= (uint)rand.Next() & 3; 
     return randNum; 
    } 
} 

Cela peut encore générer le même nombre par hasard bien sûr ...

Peut-être envisager un générateur de nombres aléatoires cryptographiques si l'entropie est importante.

+1

Même avec un CSPRNG vous pouvez obtenir le même nombre :) – Joey

+0

@Johannes - en effet, il n'y a qu'un nombre fini de nombres à contourner ... –

3

Bien, si vous ne l'utilisez que pour générer des nombres aléatoires qui ne sont jamais les mêmes, pourquoi ne pas utiliser System.Guid.NewGuid()?

+2

"jamais pareil" - bien, Guid est ** improbable ** être le même; mais ce n'est pas garanti. –

+2

Eh bien, vous ne pouvez pas aller mieux que peu probable avec un RNG de toute façon. – Joey

0

Les générateurs de nombres pseudo-aléatoires (PRNG) sont seulement aussi bons que les valeurs de germe qu'ils ont. Maintenant, je vois que vous les avez définis comme des classes statiques et des méthodes statiques, donc en supposant que vous avez mis en place une sécurité pour s'assurer que getRandomId() n'est pas appelé par plusieurs threads simultanément, alors vous devriez être en forme OK. Toutefois, le verrouillage de l'accès à getRandomId entraînera un goulot d'étranglement et ne sera pas échelonné à l'infini lorsque votre trafic augmentera.

1

Vous pouvez utiliser le mécanisme de verrouillage qui garantit qu'un seul thread à la fois peut accéder à l'objet Random.

public static class ThreadSafeRandom 
{ 
    private static Random r = new Random(); 
    public static double NextDouble() 
    { 
     lock (r) 
     { 
      return r.NextDouble(); 
     } 
    } 

    public static int Next(int min, int max) 
    { 
     lock (r) 
     { 
      return r.Next(min, max); 
     } 
    } 
} 
0

Il est toujours possible que vous génériez le même numéro lorsque vous utilisez la classe Random de base. Je ferais mieux d'utiliser System.Security.Cryptography.RandomNumberGenerator qui va créer des valeurs aléatoires cryptographiquement fortes.

1

Vous pouvez utiliser un linear congruential generator dans une fonction synchronisée pour générer des nombres pseudo-aléatoires qui ne se répètent que toutes les requêtes m (voir l'article pour en écrire une). Faites m une valeur de 64 bits, et il devient très improbable que vous aurez jamais assez de demandes pour vous répéter, et encore moins pour servir le même nombre à deux visiteurs simultanés.

+0

De plus, dans un environnement fileté, vous pouvez faire un générateur pour chacun des N travailleurs, et les étape par étape N chaque fois, de sorte que le travailleur 1 utilise X1, xN + 1, x2N + 1, ..., travailleur 2 utilise x2, xN + 2, x2N + 2 .... et il n'y a pas collisions et aucune exigence de synchronisation entre les travailleurs. –

0

Comme d'autres l'ont dit, oui vous pouvez avoir deux valeurs aléatoires identiques si les deux threads demandent la valeur aléatoire dans la même graduation.

Voici une autre implémentation aléatoire sûre du thread. Celui-ci utilise moins de verrous par requête et est donc plus rapide.

public static class ThreadSafeRandom 
{ 
    private static Random _global = new Random(); 
    [ThreadStatic] 
    private static Random _local; 

    public static int Next() 
    { 
     Random inst = _local; 
     if (inst == null) 
     { 
      int seed; 
      lock (_global) seed = _global.Next(); 
      _local = inst = new Random(seed); 
     } 
     return inst.Next(); 
    } 
} 

Voir "Getting random numbers in a thread-safe way" par l'équipe Parallels pour plus d'informations.

1

Si vous voulez un numéro de session, utilisez un GUID.