C# 并行码中的确定性随机数

C# 并行码中的确定性随机数,c#,multithreading,task-parallel-library,C#,Multithreading,Task Parallel Library,我有一个关于TPL螺纹订购的问题。 实际上,我的Parallel.for循环必须按照循环的顺序执行,这对我来说非常重要。我的意思是,给定4个线程,我希望第一个线程每4k循环执行一次,第二个线程每4k+1执行一次(k介于0和之间,NbSim/4) 第一个线程->第一个循环,第二个线程->第二个循环,第三个线程->第三个循环 第4个线程->第4个循环,第1个线程->第5个循环等 我已经看过OrderedPartition指令,但我不太确定应该如何将其应用于FOR循环,而不是Parallel.FORE

我有一个关于TPL螺纹订购的问题。 实际上,我的Parallel.for循环必须按照循环的顺序执行,这对我来说非常重要。我的意思是,给定4个线程,我希望第一个线程每4k循环执行一次,第二个线程每4k+1执行一次(k介于0和之间,NbSim/4)

第一个线程->第一个循环,第二个线程->第二个循环,第三个线程->第三个循环 第4个线程->第4个循环,第1个线程->第5个循环等

我已经看过OrderedPartition指令,但我不太确定应该如何将其应用于FOR循环,而不是Parallel.FOREACH循环

非常感谢你的帮助

按照前面的remkarks,我正在完成以下描述:

事实上,经过一些考虑,我相信我的问题不在于订购。 事实上,我正在开发一个蒙特卡罗引擎,在这个引擎中,每次迭代我都会生成一组随机数(总是相同的(seed=0)),然后对它们应用一些业务逻辑。因此,一切都应该是确定性的,当运行算法两次时,我应该得到完全相同的结果。但不幸的是,情况并非如此,我正在努力理解原因。你知道如何解决这类问题吗(不用把我所有的变量都打印出来)

编辑编号2:

谢谢大家的建议 首先,以下是我的代码的排序方式:

ParallelOptions options  = new ParallelOptions();
options.MaxDegreeOfParallelism = 4; //or 1

ParallelLoopResult res = Parallel.For<LocalDataStruct>(1,NbSim, options,
                    () => new LocalDataStruct(//params of the constructor of LocalData),
(iSim, loopState, localDataStruct) => {
    //logic
    return localDataStruct;
}, localDataStruct => {
   lock(syncObject) {
  //critical section for outputting the parameters
});
ParallelOptions=new ParallelOptions();
options.MaxDegreeOfParallelism=4//或1
ParallelLoopResult res=并行。对于(1,NbSim,选项,
()=>新建LocalDataStruct(//LocalData构造函数的参数),
(iSim、loopState、localDataStruct)=>{
//逻辑
返回localDataStruct;
},localDataStruct=>{
锁定(同步对象){
//输出参数的关键部分
});
当将degreeofParallelism设置为1时,一切正常,但是当将并行度设置为4时,我得到的结果是错误的和不确定的(当运行代码两次时,我得到的结果不同)。这可能是因为我现在检查的是可变对象,但源代码非常广泛,因此需要时间。您认为除了检查代码之外,还有一个好的策略来检查代码吗(在这种情况下,预先检查所有变量是不可能的(>1000)?另外,当将模拟的Nb设置为4对4线程时,一切都正常工作,主要是因为我相信运气好(这就是我第一次想到排序的原因)。

你可以强制执行,但要付出代价。它给出有序的结果,但不强制执行顺序

如果不序列化算法,就无法使用TPL实现这一点。TPL在任务模型上工作。它允许您调度调度程序执行的任务,而不保证任务的执行顺序。通常并行实现采用PLINQ方法,并保证结果的顺序执行顺序

为什么命令执行很重要

因此,对于Monte Carlo引擎,您需要确保数组中的每个索引都接收到相同的随机数。这并不意味着您需要对线程进行排序,只需在每个线程所做的工作中对随机数进行排序。因此,如果
ParallelForEach
的每个循环都传递了,那么不仅仅是eleme数组nts是一个随机数生成器(每个线程有一个不同的固定种子),但它本身的实例也是一个随机数生成器,那么您仍然会得到确定性的结果

我假设您熟悉与并行蒙特卡罗和生成好的随机数序列相关的挑战

一些建议

首先,我将用
ForEach
替换
ParallelForEach
,以确保您可以在顺序情况下获得确定性结果,并查看其运行是否正确。您还可以尝试比较顺序运行和并行运行的输出,添加一些诊断输出并将其传输到文本文件。然后使用diff tool来比较结果

如果这是确定的,那么这与您的并行实现有关,正如下面指出的,这通常与可变状态有关。需要考虑的一些事情:

  • 你的随机数生成器线程安全吗?
    random
    是一个很差的随机数生成器,就我所知,它不是为并行执行而设计的。它当然不适合M-C计算,并行或其他

  • 您的代码是否在线程之间共享了其他状态,如果是,它是什么?此状态将以不确定的方式发生变化,并影响您的结果

  • 您正在并行合并来自不同线程的结果。并行浮点操作的非关联性也会导致您在此处遇到问题,请参阅。即使线程结果是确定性的,如果您以非确定性的方式组合它们,您仍然会遇到问题


假设所有线程共享同一个随机数生成器,那么尽管每次都生成相同的序列,但哪个线程获取该序列的哪些元素是不确定的。因此,可能会得到不同的结果

如果随机数生成器是线程安全的,那么它甚至不能保证从多个线程调用时生成相同的序列


除此之外,很难从理论上解释导致非确定性出现的原因;基本上,任何全局可变状态都是可疑的。每个任务都应该使用自己的数据。

如果不使用随机数生成器,而是设置一个预定值的数组[0…N-1],比如[0,1/N,2/N,],并做一个
并行。ForEach
在这个问题上,它是否仍然给出不确定的r