递归异步方法失去了它的上下文

时间:2018-06-23 18:28:41

标签: f# .net-core raytracing

我正在用F#语言编写raytracer,并且试图在蒙特卡洛采样步骤中使用多线程。

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

我的当前代码:

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

如何使该方法异步递归?

1 个答案:

答案 0 :(得分:4)

我找到了问题的原因:

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