Рекурсивный асинхронный метод теряет свой контекст - PullRequest
0 голосов
/ 23 июня 2018

Я пишу raytracer на F # и пытаюсь использовать многопоточность на этапе выборки Монте-Карло.

Однако, когда я запускаю свой код с асинхронным вариантом, программа никогда не возвращается и работает бесконечно.

Мой код В настоящее время:

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 голосов
/ 25 июня 2018

Я нашел причину проблемы:

Я фактически вызывал Async.RunSynchronously из метода точки входа, т.е. rayTraceBase.Видимо вложенный Async.RunSynchronously не очень хорошая вещь.После удаления второго Async.RunSynchronously код работал.
Но он мучительно медленный, поскольку асинхронные контексты создаются повсеместно, а сборщик мусора работает без остановки.

...