Skip to content

Async.Parallel stack overflow on cancellation of ~2000 uncompleted computations #13165

@bartelink

Description

@bartelink

When Async.Parallel is handling cancellation (via the token or a computation throwing) with e.g. 2000 items outstanding, the current implementation as of FSharp.Core 6.0.4 is such that the non-tail-recursive impl can blow the stack.

Repro steps

let [<Fact>] ``Async.Parallel blows stack when cancelling many`` () =
    let gen (i : int) = async {
        if i <> 0 then do! Async.Sleep i
        else return failwith (string i) }
    let count = 1800
    let comps = Seq.init count gen
    let result = Async.Parallel(comps, 16) |> Async.Catch |> Async.RunSynchronously
    test <@ match result with
            | Choice2Of2 e -> int e.Message < count
            | x -> failwithf "unexpected %A" x @>

Known workarounds

batch the work with Seq.ChunkBySize 1500, add an outer Async.Parallel call (distributing the degreeOfParallelism over the constituent calls, or using the same value but internally constraining it with Async.Throttle), Array.concat the results.

Related information

(1800 is the approx threshold with SDK 6.0.202 on MacOS x86 with Rider test runner)

Problem appears to be at

worker trampolineHolder |> unfake

Metadata

Metadata

Assignees

No one assigned

    Labels

    Area-LibraryIssues for FSharp.Core not covered elsewhereBugImpact-Medium(Internal MS Team use only) Describes an issue with moderate impact on existing code.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions