In JavaScript, there is a function called Promise.race that takes a list of promises and returns a new promise that completes when any of the input promises completes.
See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/race
F# has Async.Parallel, which completes when all of the input asyncs have completed, but it does not seem to have an equivalent for any (such as Async.Race).
How can I write this in F#?
You could use tasks.
Something like this:
let race xs =
xs
|> Seq.map Async.StartAsTask
|> Task.WhenAny
|> Async.AwaitTask
Using Async.Choice from FSharp.Control:
let race xs =
async {
let! first =
xs
|> Seq.map (fun task -> async {
let! x = task
return Some x
})
|> Async.Choice
return Option.get first
}
Related
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
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
I am trying to make the code below working
type Message = {
Text: string
}
[<EntryPoint>]
let main argv =
use bus = RabbitHutch.CreateBus("host=localhost")
async {
let! result = bus.PubSub.PublishAsync({Text = "text"}) |> Async.AwaitTask
}
0
Knowing that PublishAsync returns Task<unit>. I just wanted to equivalently await this method in F# method but this triggers an error:
Program.fs(14, 5): [FS0010] Unexpected symbol '}' in expression
I already checked that answer on SO, not really sure what I am supposed to do, adding |> ignore does not seem to do anything.
[EDIT]
I added an ignore:
type Message = {
Text: string
}
[<EntryPoint>]
let main argv =
use bus = RabbitHutch.CreateBus("host=localhost")
async {
let! result = bus.PubSub.PublishAsync({Text = "text"}) |> Async.AwaitTask
result |> ignore
}
0
But now I get the following warning:
Program.fs(10, 5): [FS0020] The result of this expression has type 'Async<unit>' and is implicitly ignored. Consider using 'ignore' to discard this value explicitly, e.g. 'expr |> ignore', or 'let' to bind the result to a name, e.g. 'let result = expr'.
Can't get rid of that one though, any idea?
The result of this expression:
async {
let! result = bus.PubSub.PublishAsync({Text = "text"}) |> Async.AwaitTask
result |> ignore
}
is a value of Async<unit> type. In F# and functional programming, every expression should contribute to the result of the bigger expression, otherwise it is likely a mistake. Hence your compiler reported the warning.
To tell compiler that you are okay with that, simply transform the value to the () value of the unit type (which is similar to void type in other languages) by using the ignore function.
Now look into the body of your async, in your old code, the last statement is let! result = ... and it is invalid in F# syntax. Every let or let! is the short form of let name=... in someExpression but there is no expression here except the } that’s why compiler said Unexpected symbol '}' in expression.
You fixed that by piping result to ignore. That’s okay because that is a valid expression.
Now consider your new code, you can ignore the Async<unit> to dismiss the warning, but that makes your async nonsense. You declared the async, but did not execute it. Probably you need to execute it with the Async.RunSynchronously function:
async {
let! result = bus.PubSub.PublishAsync({Text = "text"}) |> Async.AwaitTask
result |> ignore
}
|> Async.RunSynchronously
Since result is a unit value, you can clean your code with do!:
async {
do! bus.PubSub.PublishAsync({Text = "text"}) |> Async.AwaitTask
}
|> Async.RunSynchronously
Or even cleaner:
bus.PubSub.PublishAsync({Text = "text"})
|> Async.AwaitTask
|> Async.RunSynchronously
Your async computation expression returns Async<unit>. You need to actually run the computation. You can do that with Async.RunSynchronously.
async {
let! result = bus.PubSub.PublishAsync({Text = "text"}) |> Async.AwaitTask
result |> ignore
} |> Async.RunSynchronously
Though at this point, I think the computation expression is redundant. This would do the same:
bus.PubSub.PublishAsync({Text = "text"})
|> Async.AwaitTask
|> Async.RunSynchronously
Suppose I have some C# code that takes a callback:
void DoSomething(Action<string> callback);
Now, I want to use this in F#, but wrap it in an async. How would I go about this?
// Not real code
let doSomething = async {
let mutable result = null
new Action(fun x -> result <- x) |> Tasks.DoSomething
// Wait for result to be assigned
return result
}
For example, suppose DoSomething looks like this:
module Tasks
let DoSomething callback =
callback "Hello"
()
Then the output of the following should be "Hello":
let wrappedDoSomething = async {
// Call DoSomething somehow
}
[<EntryPoint>]
let main argv =
async {
let! resultOfDoSomething = wrappedDoSomething
Console.WriteLine resultOfDoSomething
return ()
} |> Async.RunSynchronously
0
The function Async.FromContinuations is, so to say, the "lowest level" of Async. All other async combinators can be expressed in terms of it.
It is the lowest level in the sense that it directly encodes the very nature of async computations - the knowledge of what to do in the three possible cases: (1) a successful completion of the previous computation step, (2) a crash of the previous computation step, and (3) cancellation from outside. These possible cases are expressed as the three function-typed arguments of the function that you pass to Async.FromContinuations. For example:
let returnFive =
Async.FromContinuations( fun (succ, err, cancl) ->
succ 5
)
async {
let! res = returnFive
printfn "%A" res // Prints "5"
}
|> Async.RunSynchronously
Here, my function fun (succ, err, cancl) -> succ 5 has decided that it has completed successfully, and calls the succ continuation to pass its computation result to the next step.
In your case, the function DoSomething expresses only one of the three cases - i.e. "what to do on successful completion". Once you're inside the callback, it means that whatever DoSomething was doing, has completed successfully. That's when you need to call the succ continuation:
let doSometingAsync =
Async.FromContinuations( fun (succ, err, cancl) ->
Tasks.DoSomething( fun res -> succ res )
)
Of course, you can avoid a nested lambda-expression fun res -> succ res by passing succ directly into DoSomething as callback. Unfortunately, you'll have to explicitly specify which type of Action to use for wrapping it, which negates the advantage:
let doSometingAsync =
Async.FromContinuations( fun (succ, err, cancl) ->
Tasks.DoSomething( System.Action<string> succ )
)
As an aside, note that this immediately uncovered a hole in the DoSomething's API: it ignores the error case. What happens if DoSomething fails to do whatever it was meant to do? There is no way you'd know about it, and the whole async workflow will just hang. Or, even worse: the process will exit immediately (depending on how the crash happens).
If you have any control over DoSomething, I suggest you address this issue.
You can try something like:
let doSomething callback = async {
Tasks.DoSomething(callback)
}
If your goal is to define the callback in the method you could do something like:
let doSomething () = async {
let callback = new Action<string>(fun result -> printfn "%A" result )
Tasks.DoSomething(callback)
}
If your goal is to have the result of the async method be used in the DoSomething callback you could do something like:
let doSomething =
Async.StartWithContinuations(
async {
return result
},
(fun result -> Tasks.DoSomething(result)),
(fun _ -> printfn "Deal with exception."),
(fun _ -> printfn "Deal with cancellation."))
I'm playing around asynchronous programming and was wondering if there's a function that exists that can take a value of type 'T and transform it to an Async<'T>, similar to C#'s Task.FromResult that can take a value of type TResult and transform it to a Task<TResult> that can then be awaited.
If such a function does not exist in F#, is it possible to create it? I can kind of emulate this by using Async.AwaitTask and Task.FromResult, but can I do this by only using Async?
Essentially, I'd like to be able to do something like this:
let asyncValue = toAsync 3 // toAsync: 'T -> Async<'T>
let foo = async{
let! value = asyncValue
}
...or just async.Return
let toAsync = async.Return
let toAsync` x = async.Return x
moreover there is async.Bind (in tupled form)
let asyncBind
(asyncValue: Async<'a>)
(asyncFun: 'a -> Async<'b>) : Async<'b> =
async.Bind(asyncValue, asyncFun)
you could use them to make pretty complicated async computation without builder gist link
let inline (>>-) x f = async.Bind(x, f >> async.Return)
let requestMasterAsync limit urls =
let results = Array.zeroCreate (List.length urls)
let chunks =
urls
|> Seq.chunkBySize limit
|> Seq.indexed
async.For (chunks, fun (i, chunk) ->
chunk
|> Seq.map asyncMockup
|> Async.Parallel
>>- Seq.iteri (fun j r -> results.[i*limit+j]<-r))
>>- fun _ -> results
You can use return within your async expression:
let toAsync x = async { return x }
I have the following code in F# 4.0
let processEscalation escalationAction (escalationEvents:UpdateCmd.Record list) =
printf "%A" Environment.NewLine
printf "Started %A" escalationAction
escalationEvents
|> List.iter ( fun x ->
printf "%A" Environment.NewLine
printf "escalation %A for with action: %A" x.incident_id escalationAction
service.PostAction(new Models.Action(x.incident_id, escalationAction, "escalated"))
|> Async.AwaitTask
|> ignore)
let ComposeEscalation() =
let escalationlevels = ["ESC1 REACHED"; "ESC2 REACHED"; "ESC3 REACHED"]
escalationlevels
|> List.map getEscalationEvents
|> List.iteri (fun i x -> processEscalation escalationlevels.[i] x)
where the following line is a call to a C# async method that that returns Task
service.PostAction(new Models.Action(x.incident_id, escalationAction, "escalated"))
The compose escalation method calls the processEscalation three times.
However, the second call starts before the first call is complete.
How can I make sure that the the last line, list.iteri awaits and processes them sequentially?
Perhaps the processEscalation should be in an async computation expression?
What Async.AwaitTask does is that it returns an Async computation that can be used to wait for the task to complete. In your case, you never do anything with it, so the loop just proceeds to the next iteration.
You want something like this:
service.PostAction(new Models.Action(x.incident_id, escalationAction, "escalated"))
|> Async.AwaitTask
|> Async.RunSynchronously
|> ignore
This should have the effect you expect, though certainly there are nicer, more composable ways of expressing such logic.
Edit: What I meant was something like this, a counterpart to the core Async.Parallel function:
module Async =
let sequential (asyncs: seq<Async<'t>>) : Async<'t []> =
let rec loop acc remaining =
async {
match remaining with
| [] -> return Array.ofList (List.rev acc)
| x::xs ->
let! res = x
return! loop (res::acc) xs
}
loop [] (List.ofSeq asyncs)
Then you can do something along these lines:
escalationEvents
// a collection of asyncs - note that the task won't start until the async is ran
|> List.map (fun x ->
async {
let task =
service.PostAction(new Models.Action(x.incident_id, escalationAction, "escalated"))
return! Async.AwaitTask task
})
// go from a collection of asyncs into an async of a collection
|> Async.sequential
// you don't care about the result, so ignore it
|> Async.Ignore
// now that you have your async, you need to run it in a way that makes sense
// in your context - Async.Start could be another option.
|> Async.RunSynchronously
The upside here is that instead of bundling everything into a single loop, you've split the computation into well-delimited stages. It's easy to follow and refactor (e.g. if you need to process those events in parallel instead, you just switch out one step in the pipeline).