Home > Net >  In F# how do I create a list of Async<unit> inside an async computation without mutable collec
In F# how do I create a list of Async<unit> inside an async computation without mutable collec

Time:10-21

I have a small program using the producer/consumer pattern in F#. I want to start 1 producer, then 8 consumers, wait for the producer then wait for the consumers and end the program.

The code that sets this in motion is:

async {
    let! p = Async.StartChild producer
    let maxConcurrent = 8

    let consumers = List<Async<unit>>()

    for _ in 0 .. maxConcurrent - 1 do
        let! c = Async.StartChild consumer
        consumers.Add(c)

    do! p

    for i in 0 .. maxConcurrent - 1 do
        do! consumers[i]

}
|> Async.RunSynchronously

While this works it feels wrong to use the mutable List from System.Collections.Generic instead of just F# list. But I cannot generate the list of Async needed using List. I have tried:

let consumers2 = List.init 8 (fun _ -> async {
        let! c = Async.StartChild consumer
        return c
})

But this now wraps it in async again, so it becomes a list<async<async<unit>>>, if it's instead return! then the app hangs (I'm guessing because I'm not awaiting the task that should start the Task instead awaiting also the task that awaits finalization)

Full code is available here

CodePudding user response:

I think Async.Parallel will flatten the asyncs the way you want. The following seems to work correctly for me:

async {
    // I need the producer to run in it's own thread, not shared by the threadpool, because I rely on the consumer being allowed to block the thread with .Take
    let! p = Async.StartChild producer

    let maxConcurrent = 8
    let! consumers =
        List.init maxConcurrent (fun _ ->
            Async.StartChild consumer)
            |> Async.Parallel

    do! p

    for c in consumers do
        do! c
}
|> Async.RunSynchronously
  • Related