Question

J'ai un code Fortran90 parallèle dans lequel chaque thread doit générer la même séquence de nombres aléatoires.

J'ai un générateur de nombres aléatoires qui semble être thread-unsafe, car, pour une graine donnée, je suis complètement incapable de répéter les mêmes résultats à chaque fois que je lance le programme.

J'ai navigué (presque) sans succès sur tout le Web à la recherche du code d'un générateur de ressources naturelles thread-safe. Quelqu'un pourrait-il me fournir (le lien vers) le code de l'un?

Merci d'avance!

Était-ce utile?

La solution

Un bon générateur de nombres pseudo-aléatoires pour Fortran90 se trouve dans le Bibliothèque statistique de vecteurs Intel Math Kernel . Ils sont thread-safe. Aussi, pourquoi faut-il être threadsafe? Si vous voulez que chaque thread obtienne la même liste, instanciez un nouveau PRNG pour chaque thread avec le même germe.

Autres conseils

La plupart des générateurs de nombres aléatoires répétables ont besoin d'un état sous une forme ou une autre. Sans Etat, ils ne peuvent pas faire ce qui va suivre. Pour être thread-safe, vous avez besoin d'un moyen de conserver l'état vous-même (autrement dit, il ne peut pas être global).

Lorsque vous dites "besoin de générer la même séquence de nombres aléatoires" voulez-vous dire que

  • Chaque thread doit générer un flux de nombres identiques à l'autre? Cela implique de choisir la graine avant de retirer les threads, puis d’instancier un PRNG de thread local dans chaque thread avec la même graine.

ou

  • Vous voulez pouvoir répéter la même séquence de nombres entre différentes exécutions des programmes, mais chaque fil génère sa propre séquence indépendante? Dans ce cas, vous ne pouvez toujours pas partager un seul PRNG car la séquence d'opérations de thread n'est pas déterministe. Par conséquent, ensemencez un seul PRNG avec une graine connue avant de lancer les threads et utilisez-le pour générer les graines initiales des threads. Puis vous instanciez des générateurs de threads locaux dans chaque thread ...

Dans chacun de ces cas, notez ce que Neil Butterworth dire sur les statistiques: la plupart des garanties habituelles que le PRNG aime à réclamer ne sont pas fiables lorsque les flux de mixage générés de cette manière.

Dans les deux cas, vous avez besoin d'un PRNG au niveau du thread. Je ne sais pas ce qui est disponible dans f90 ... mais vous pouvez aussi écrire vous-même (lookup Mersenne Twister et écrivez une routine qui prend comme état l'état enregistré en tant que paramètre ...).

Dans Fortran 77, cela ressemblerait à quelque chose comme

      function PRNGthread (state)

      double state(statesize)

c stuff happens here which uses and manipulates the state vector...

      PRNGthread = result
      return 

et chacun de vos threads doivent conserver un vecteur d'état distinct, même s'ils utiliseront la même valeur initiale.

Je comprends que vous avez besoin que chaque thread produise le même flux de nombres aléatoires.

Un très bon générateur pseudo-aléatoire générant un flux de nombres reproductible et assez rapide est le MT19937 . Assurez-vous simplement que vous générez le germe avant de générer les threads, mais générez une instance distincte du MT dans chaque thread (rendez l'instance du thread MT locale). De cette façon, il sera garanti que chaque MT produira le même flux de nombres.

Qu'en est-il de SPRNG ? Je ne l’ai pas essayé moi-même cependant.

J'ai codé une version Fortran 90 de Mersenne Twister / MT19973 en mode thread-safe. L'état du PRNG est enregistré dans un type dérivé (randomNumberSequence) et vous utilisez des procédures pour initialiser le générateur ou obtenir l'élément suivant de la séquence.

Voir http: //code.google.com/p/i3rc-monte-carlo-model/source/browse/trunk/Code/RandomNumbersForMC.f95

Les alternatives semblent être:

  • Utilisez un objet de synchronisation (tel que un mutex) sur la graine du générateur valeur. Ce sera malheureusement sérialiser votre code sur les accès à générateur
  • Utiliser le stockage local des threads dans la générateur de sorte que chaque fil obtient son propre graine - cela peut causer des effets statiques problèmes pour votre application
  • Si votre plate-forme prend en charge un opération atomique, utilisez-le sur le graine (ce ne sera probablement pas, cependant)

Liste pas très encourageante, je sais. Et pour ajouter à cela, je n’ai aucune idée de la manière de les implémenter dans Fortran!

Cet article https://www.cmiss.org/openCMISS/wiki/RandomNumberGenerationWithGenerationWithOpenMP ne fait pas seulement référence à une implémentation Fortran, mais mentionne les points clés nécessaires pour rendre un PRNG utilisable avec des threads. Le point le plus important est:

La version Fortran90 de Ziggurat comporte plusieurs variables et tableaux dotés de l'attribut 'SAVE'. Afin de paralléliser le RNG uniforme, il apparaît donc que les modifications requises consistent à créer des tableaux de variables avec une valeur distincte pour chaque thread (méfiez-vous du faux partage). Ensuite, lorsque la fonction PRNG est appelée, nous devons passer le numéro de thread et utiliser la valeur d'état correspondante.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top