【问题标题】:Recursive async method looses its context递归异步方法失去其上下文
【发布时间】:2018-06-25 05:43:56
【问题描述】:

我正在用 F# 编写光线追踪器,并尝试在 montecarlo 采样步骤中使用多线程。

但是,当我使用异步变体运行我的代码时,程序永远不会返回并无限期地运行。

我目前的代码:

let rec rayTrace previousTraceDepth ((ray : Ray) , (accEmitted : Color) , (accScatter :Color)) =
if previousTraceDepth > maxTraceDepth 
then  
    accEmitted + backgroundColor*accScatter
else
    let newTraceDepth = previousTraceDepth + 1us
    let (realSolution,t,surface) = findClosestIntersection ray surfaces
    let surfaceGeometry : Hitable = surface.Geometry
    if surfaceGeometry.IntersectionAcceptable realSolution t 1.0f (PointForRay ray t)
    then
        let emittedShading = surface.Emitted
        let e = accEmitted + accScatter*emittedShading 
        let mcSamples = surface.SampleCount

        //Synchronous
        // let mutable totalShading = e/surface.MCNormalization
        // for _ in 1..mcSamples do
        //     let (doesRayContribute,outRay,cosOfIncidence) = surface.Scatter ray t ((int)newTraceDepth)
        //     let shading = surface.BRDF*cosOfIncidence / (surface.PDF*surface.MCNormalization)
        //     let s = accScatter*shading
        //     totalShading <- totalShading + (rayTrace newTraceDepth (outRay , e , s))
        // totalShading

        let eMCAdjusted = e / surface.MCNormalization
        let shadingSamplesAsync = 
           [|
               for _ in 1..mcSamples -> async {
                       let (doesRayContribute,outRay,cosOfIncidence) = surface.Scatter ray t ((int)newTraceDepth)
                       let shading = surface.BRDF*cosOfIncidence / (surface.PDF*surface.MCNormalization)
                       let s = accScatter*shading
                       return rayTrace newTraceDepth (outRay,e,s)
                   }|]

        if Array.isEmpty shadingSamplesAsync then 
            e
        else
            let shadingSamplesSync = shadingSamplesAsync |> Async.Parallel |> Async.RunSynchronously
            Array.sumBy (fun x -> eMCAdjusted + x) shadingSamplesSync

    else 
       accEmitted + backgroundColor*accScatter

我怎样才能使这个方法异步递归?

【问题讨论】:

    标签: f# .net-core raytracing


    【解决方案1】:

    我找到了问题的原因:

    我实际上是从入口点方法(即rayTraceBase)调用Async.RunSynchronously。显然嵌套Async.RunSynchronously 不是一件好事。在我删除第二个 Async.RunSynchronously 后,代码起作用了。
    但它非常缓慢,因为异步上下文是在各处创建的,并且 GC 会不停地运行。

    【讨论】:

    • 异步不适合像您这样的计算密集型用例。更好的方法是编写普通(同步)函数并在更高级别上与 Array.Parallel.map 并行化。我会为像素创建一个输入数组,并与 Array.Parallel.map 并行计算它们。
    • 感谢您的意见。我现在正在这样做。虽然没有平行图。这是你的想法吗?:let colorSamplesBatch = [|for i in 1..batchSize -&gt; async {return rayTraceBase ray px py i}|]let colorsBatch = colorSamplesBatch |&gt; Async.Parallel |&gt; Async.RunSynchronously
    • 并非如此。我的意思是您根本不应该使用async,而是使用Array.Parallel.map (msdn.microsoft.com/en-us/visualfsharpdocs/conceptual/…) 并在更高级别上执行此操作,因为无论如何您都无法并行计算数百个计算密集型任务。类似let pixels = pixelCoordinatesArray |&gt; Array.Parallel.map rayTrace
    • 是的,你是对的。我将异步与并发计算混淆了。谢谢!
    • 但是,在我的情况下,异步工作流似乎更快
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-05-13
    • 1970-01-01
    • 1970-01-01
    • 2011-09-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多