Parallel processing F#Array.Parallel.map不提供并行处理

Parallel processing F#Array.Parallel.map不提供并行处理,parallel-processing,functional-programming,f#,deadlock,mailboxprocessor,Parallel Processing,Functional Programming,F#,Deadlock,Mailboxprocessor,我必须在F#中模拟一个离散环境,由Python调用,用于强化学习问题。我有一个带有基本类型(主要是float)的函数,可以使数据交换更加顺畅。现在我可以用不同的数据多次运行这个函数,所以并行运行它似乎是个好主意 我有以下代码: type AscentStrategy = |Strategy of seq<float> let simulateAscent env ascentLimiter initState (sequenceOfDepths:seq<float>

我必须在F#中模拟一个离散环境,由Python调用,用于强化学习问题。我有一个带有基本类型(主要是float)的函数,可以使数据交换更加顺畅。现在我可以用不同的数据多次运行这个函数,所以并行运行它似乎是个好主意

我有以下代码:

type AscentStrategy = |Strategy of seq<float> 

let simulateAscent  env ascentLimiter initState (sequenceOfDepths:seq<float>)  =   
    //let infinitSeqOfConstantValues = (fun _ -> constantDepth) |> Seq.initInfinite
    sequenceOfDepths 
    |> Seq.scan ( fun ( nextState, rew, isTerminal, _ )  depth -> getNextEnvResponseAndBoundForNextAction(env, nextState , depth , ascentLimiter)  ) (  initState, 0.0 , false, 0.0)  
    |> SeqExtension.takeWhileWithLast (fun (_ , _, isTerminalState, _) ->  not isTerminalState)
    |> Seq.toArray

and then 

    let simulateStrategy ({MaxPDCS = maxPDCS ; MaxSimTime = maximumSimulationTime ; PenaltyForExceedingRisk = penaltyForExceedingRisk ; 
                       RewardForDelivering = rewardForDelivering ; PenaltyForExceedingTime = penaltyForExceedingTime ; IntegrationTime = integrationTime 
                       ControlToIntegrationTimeRatio = controlToIntegrationTimeRatio; DescentRate = descentRate; MaximumDepth = maximumDepth ; 
                       BottomTime = bottomTime ; LegDiscreteTime = legDiscreteTime } : SimulationParameters) (Strategy ascentStrategy : AscentStrategy) = 
    
    let env, initState ,  ascentLimiter , _  =  getEnvInitStateAndAscentLimiter  ( maxPDCS    , maximumSimulationTime , 
                                                                           penaltyForExceedingRisk ,  rewardForDelivering , penaltyForExceedingTime , 
                                                                           integrationTime  ,
                                                                           controlToIntegrationTimeRatio,  
                                                                           descentRate , 
                                                                           maximumDepth  , 
                                                                           bottomTime  , 
                                                                           legDiscreteTime   ) 
    ascentStrategy
    |> simulateAscent  env ascentLimiter initState
let nessosResult = inputsStrategies
                    |> ParStream.ofArray
                    |> ParStream.map simulateStrategy
                    |> ParStream.toArray
我将其与Array.map进行了比较,虽然它速度更快,占用了笔记本电脑70%的CPU,但似乎仍然没有使用全部处理能力。我在一台拥有更多内核(约50个)的机器上运行过它,它几乎不会增加CPU使用率(在50个独立输入的情况下,它的使用率高达总使用率的3/4%)。我想一定是某个地方产生了死锁,但我如何才能检测到并消除它呢

还有,为什么会发生这种情况?在我看来,函数式编程的优点之一就是能够轻松地并行化

PS:SeqExtension.takeWhileWithLast是我在SO上找到的一个函数,由Tomas Petricek在他的一个精彩答案中提供,如果需要,我可以发布它

PPS:env是环境,其类型定义为:

type Environment<'S, 'A ,'I>         =   |Environment of (State<'S> -> Action<'A> -> EnvironmentOutput<'S ,'I>)
我已经为inputStrategy定义了一个特殊类型(基本是我以前的元组),这样simulateStrategy只接受一个输入。不幸的是,这个问题似乎隐藏在某个地方。我附加了一个CPU使用率图表。对于不同的情况,我在机器上花费的时间为:~8.8秒(连续)~6.2秒(Array.Parallel.map);~6.1秒(Nessos.Streams)

我发现在.NET上获得最佳并行性能是必要的。在您的app.config中类似于以下内容:



输入策略从哪里来?它们是如何生成的?@FyodorSoikin它们是用于测试的玩具序列。我生成n个具有常量值的序列。我添加了用于测试代码是否并行运行的玩具代码。ThanksParallel确实使用了多个内核,但隐藏锁(如您似乎正在使用的Seq中的锁)可能会限制它实现的并行性。如果你不能创建一个你在这里共享的最小可复制的程序,那么我建议你试着从简单开始,例如
Parallel.for
,观察它实现的并行性,并从那里扩展,直到你明白是什么扼杀了并行性。旁注;我曾经对并行实现性能感到非常兴奋,但我得出的结论是,这很难,而且你可能买不起好的抽象。谢谢。恐怕你是对的。我的代码有点抽象(可能太多了,但我希望在很多方面都可以重用);我不知道这会给并行性带来问题。不过,布莱恩伯恩斯的回答帮助很大。ThanksIt并没有解决整个问题,但确实缩短了时间。在我的笔记本电脑上,它似乎充分利用了所有的4个CPU,在80核的Xeon上,它仍然缺乏完全的并行性,但从时间上看,它从2X(wrt到顺序解决方案)增加到了10X,这已经是一个很好的改进。谢谢
let nessosResult = inputsStrategies
                    |> ParStream.ofArray
                    |> ParStream.map simulateStrategy
                    |> ParStream.toArray