并行随机数序列,与线程数无关

时间:2014-04-05 11:08:20

标签: multithreading random scientific-computing deterministic

这里有大量平行的RNG问题,但我找不到一个解决我的变体的问题。

我正在编写一个函数,给定一个种子用基于该种子的随机数填充长数组。我目前按顺序执行此操作,但我发现RNG占用了我程序的大量运行时间。因此,我希望通过使用多个线程来加速我的功能。但我希望这对用户透明。也就是说,给定一个种子,应该得到相同的随机数序列,与函数内部使用的线程数无关。

我目前的想法是将数组划分为块(独立于线程数),并为每个块生成新的RNG,例如通过为种子+ chunk_id播种每个RNG。然后可以独立地处理块,并且哪个线程处理哪个块无关紧要。但我担心这可能会降低RNG的质量。对于像mersenne twister这样的高品质RNG来说,这是一种安全的方法吗?

为了说明,这里有一些伪代码:

function random(array, seed, blocksize=100000)
  for each block of size blocksize in array
    rng[block] = create_rng(seed+i)
  parallel for each block in array
    for each sample in block
      array[sample] = call_rng(rng[block])

这应该为每个(种子,块大小)组合产生相同的值。但这是最好的方法吗?

1 个答案:

答案 0 :(得分:1)

我使用TestU01 random number generator test suite通过构建自定义RNG来测试此方法的有效RNG质量,该RNG每隔0x1000步重新接种一个新的顺序种子:

#include <stdlib.h>
#include "ulcg.h"
#include "unif01.h"
#include "bbattery.h"

long long i=1,j=0;
unif01_Gen * gen;

unsigned long myrand()
{
  if(++i&0xfff==0)
  {
    ugfsr_DeleteGen(gen);
    gen = ugfsr_CreateMT19937_02(++j, NULL, 0);
  }
  return gen->GetBits(gen->param, gen->state);
}

int main()
{
  unif01_Gen *gen2 = unif01_CreateExternGenBitsL("foo", myrand);
  gen = ugfsr_CreateMT19937_02(1, NULL, 0);
  bbattery_Crush (gen2);
  return 0;
}

结果(等待40分钟完成测试后):

      Test                          p-value
----------------------------------------------
71  LinearComp, r = 0              1 - eps1
72  LinearComp, r = 29             1 - eps1
----------------------------------------------
All other tests were passed

这些测试是相同的测试Mersenne Twister即使在正常使用时也会失败,而不是重新播种。因此,TestU01 Crush测试无法将顺序播种场景与正常使用区分开来。

我还测试了使用另一个Mersenne Twister的输出重新接种的方法,而不是使用顺序整数。结果完全一样。

虽然我没有尝试过最耗时的&#34; BigCrush&#34;测试(花费8小时),我认为可以肯定地说,通过生成具有连续种子的子RNG,MT的质量没有明显受损,如问题中所示。