Home > Enterprise >  How to update a counter from an async process in F#
How to update a counter from an async process in F#

Time:07-01

I need to run a process that runs something from a list - it doesn't really matter what order it runs in - but I want it to update a global "counter" when it has completed each task so that I can see the progress somewhere else ( maybe using something like signal R )

I used to do this stuff in an object-oriented way - but trying to be a little more "functional".

let doSomethingElse(value: int) = async{
    // Update a global counter incrementing it by 1
    return true
}

let doSomething() = async{
    let values = [2; 4; 6; 8]
    let! newList = values |> List.map(fun value -> doSomethingElse(value)) |> Async.Parallel
    return true
}

CodePudding user response:

Following what @JL0PD mentioned you could do something like the following.

[<RequireQualifiedAccess>]
module Async =
    let tee (f: _ -> unit) a =
        async {
            let! r = a
            f r
            return r
        }

module Counter =
    let create () =
        let mutable counter = 0
        let increment =
            fun _ ->
                counter <- counter   1
                ()
        (increment, fun () -> counter)

let doSomethingElse(value: int) = async {
    return value % 2
}

let doSomething() = async {
    let values = [1; 2; 4; 6; 8; 9]
    let increment, getCount = Counter.create()

    let doSomethingElseWithProgress =
        doSomethingElse
        >> (Async.tee increment)

    let! _ =
        values
        |> List.map doSomethingElseWithProgress
        |> Async.Parallel
    return getCount() = (List.length values)
}

doSomething ()
|> Async.RunSynchronously

I do recommend doing something better than a mutable counter, specially since you are dealing with parallel tasks.

In this case I'm composing doSomethingElse and increment using tee, this way doSomethingElse don't have to know (and call) an external function.

  • Related