F#: How can I wrap a non-async value in Async<'T>? - asynchronous

In F#, I'm implementing an interface that returns Async<'T>, but my implementation does not require any async method calls. Here's an example of my current implementation:
type CrappyIdGeneratorImpl() =
interface IdGenerator with
member this.Generate(): Async<Id> = async {
return System.Guid.NewGuid().ToString()
}
Is this the "best" way to wrap a non-Async<> value in Async<>, or is there a better way?
Put another way, I'm looking for the Async equivalent of System.Threading.Tasks.Task.FromResult().

Yes, that's the best way.
Note that, as stated in the comment, another way would be to do async.Return but it's not exactly the same thing, and in your use case it won't work, due to eager evaluation of the argument.
In your case you're interested in calling the .NewGuid() method each time the async is run, but if you use async.Return alone it will be evaluated once and the async computation will be created with that result as a fixed value.
In fact the equivalent of the CE is async.Delay (fun () -> async.Return (.. your expression ..))
UPDATE
As Tarmil noted, this can be interpreted as intended, given that the code resides in a method.
It might be the case that you created a method because that's the way you do with tasks, but Asyncs can be created and called independently (hot vs cold async models).
The question of whether the intention is delaying the async or creating an async at each method call is not entirely clear to me, but whichever is the case, the explanation above about each approach is still valid.

Related

F#: Synchronously start Async within a SynchronizationContext

Async.SwitchSynchronizationContext allows an Async action to switch to running within a given SynchronizationContext. I would like to synchronously begin an Async computation within a SynchronizationContext, rather than switching inside the Async.
This would ensure that Async actions are run in the desired order, and that they are not run concurrently.
Is this possible? The documentation for Async.SwitchSynchronizationContext mentions using SynchronizationContext.Post, but no such functionality is exposed for Async.
I have not tested this, but I think the easiest way to achieve what you want is to combine the SynchronizationContext.Send method (mentioned in the comments) with the Async.StartImmediate operation. The former lets you start some work synchronously in the synchronization context. The latter lets you start an async workflow in the current context.
If you combine the two, you can define a helper that starts a function in a given synchronization context and, in this function, immediately starts an async workflow:
let startInContext (sync:SynchronizationContext) work =
SynchronizationContext.Current.Send((fun _ ->
Async.StartImmediate(work)), null)
For example:
async {
printfn "Running on the given sync context"
do! Async.Sleep(1000)
printfn "Should be back on the original sync context" }
|> startInContext SynchronizationContext.Current

how to start one flux after completion of another?

how can i start Flux after completion of Flux? Flux doesn't depend on result of Flux.
I thought operation then() should do the work, but it just return mono. So what is the correct operator?
Flux.thenMany is the operator that you need
abstract Flux<Integer> flux1();
abstract Flux<String> flux2();
public Flux<String> flux2AfterFlux1(){
return flux1().thenMany(flux2());
}
My reply is late, so you have probably either figured this out, or moved on. I need to do the same thing, so I seem to have achieved this by using Flux.usingWhen(). I need to obtain IDs from my database that exhibit a certain property. After retrieving these IDs, then I need to get some information about these IDs. Normally, a join would work, but I am using MongoDB, and joins are horrible, so it is better to do separate, sequential queries. So let's say I have a Mongo reactive repository with a method called Flux<String> findInterestingIds(). I have another method in the same repository called Flux<String> findInterestingInformation(String[] interestingIds) that I need to feed the IDs found in the call to the previous method. So this is how I handle it:
Mono<List<String>> interestingIdsMono = myRepo.findInterestingIds()
.collectList();
Flux.usingWhen(interestingIdsMono,
interestingIds -> myRepo.findInterestingInformation(interestingIds),
interestingIds -> Flux.empty().doOnComplete(() -> log.debug("Complete"));
The cleanup function (third parameter) was something that I don't quite yet understand how to use in a good way, so I just logged completion and I do not need to emit anything extra when the flux completes.
ProjectReactor used to have a compose function that is now called transformDeferred, and I had some hopes for that, but I do not quite see how it would apply in this type of situation. At any rate, this is my attempt at it, so feel free to show me a better way!

Why do functions have to be async in order to use await within them?

If I want to await a function, why does that have to be done in an async function only?
If I have this:
Function myFunc() {
return await myOtherFunc();
}
I get an error saying: “await expression is only allowed within an asynchronous function.”
I can understand if myOtherFunc() had to be asynchronous (it doesn't make sense to await an asynchronous function), but why does it care if the calling function is asynchronous or not. You can have a fork in a process within a synchronous function due to a call to an asynchronous function, right? So then why can’t you await that asynchronous function within the synchronous function?
NOTE: my question is NOT a duplicate of Javascript Await/Async Feature - What if you do not have the await word in the function?.
^ that question is asking what happens if await is not used in an async function. I'm asking why the function has to be async in order to use await. My response to DougBug below explains why they are different.
The picture in the following article might help explain it to you a bit.
https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/async/index
The basic idea though is that the async keyword allows the function to yield its execution up to a calling function.
As such any function that implements await must be marked async so that it can traverse back up the calling path until the first caller is only waiting on it to complete what it needs to do.

Round robin concurrent algorithm with F# and Task<T>

I have a C# API like this:
Task<T> Foo(serverUri)
Let's say I have 4 possible serverUris. I want to implement a function that will return DiscUnionBar type:
type DiscUnionBar of T =
Safe of T | Weak of T | ConnectionError
The implementation will have the following requirements:
Do 3 (max) concurrent calls to Foo() with 3 different serverUris.
Pick the 2 fastest successful responses. If they give same result T1 and T2 (being T1==T2), stop doing concurrent requests and ignore/cancel requests that are in progress and return Safe of T. If T1!=T2, keep doing more requests (or looking at responses) until two equal responses are found.
If any of the requests fails (throws ServerException), try with a serverUri that has not been requested before.
If all requests to all 4 servers fail, return ConnectionError.
If only 1 request succeeds, return Weak of T.
Is this easy to do given that I cannot use F#'s Async and have to stick with C#'s Task usage? I'm a bit lost on this one.
Unless there is a reason you cannot use Async anywhere in your code, and your only limitation is that Foo has to return a Task, you should have no problem converting the Task resulting from calling Foo to an Async with Async.AwaitTask.
This way you can build the logic using F#'s async computation expressions as if Foo returned an Async
let simpleComputation serverUri = async {
let! fooResult = Foo(serverUri) |> Async.AwaitTask
(* here you can work with the T returned by Foo's task *)
}
I also have good experience with FSharp.Control.FusionTasks library, which lets you use Task directly in async computation expressions, without having to call AwaitTask explicitly, and helps in Async/Task interop in general. Although some may not like that it tries to hide the Tasks.

WPF background operations using Asynchronous Workflows

To execute operations on a background thread and avoid blocking the UI in a WPF application, I often find myself writing this pattern:
async {
// some code on the UI thread
let uiThread = SynchronizationContext.Current
do! Async.SwitchToThreadPool()
let! result = // some Async<'t>
do! Async.SwitchToContext uiThread
// do things with the result if it wasn't () all along
}
Am I doing this right at all? Is this idiomatic? Should it be done differently?
If this is correct, of course I would prefer not to have to do it like that all the time - is there a built-in shorter way to achieve the same thing? None of the existing Async functions appears to do something like that.
If not, does it make sense to just turn the above code into a function?
let onThreadPool operation =
async {
let context = SynchronizationContext.Current
do! Async.SwitchToThreadPool()
let! result = operation
do! Async.SwitchToContext context
return result
}
That adds another level of async { } nesting - can this cause issues at "some" point?
What you're doing here definitely makes sense. One useful operation here is Async.StartImmediate, which starts the async workflow on the current thread. If you call this from the UI thread, this guarantees that the workflow will also start on the UI thread and so you can capture the synchronization context inside the workflow.
The other trick is that many built-in asynchronous F# operations automatically jump back to the original synchronization context (those that are created using Async.FromContinuations, including e.g. AsyncDownloadString), so when you're calling one of those, you do not even need to explicitly jump back to the original synchronization context.
But for other asynchronous operations (and for non-async operations that you want to run in the background), your onThreadPool function looks like a great way of doing this.
#random-dev is right capturing the context must happen outside the workflow
let onThreadPool operation =
let context = SynchronizationContext.Current
async {
do! Async.SwitchToThreadPool()
let! result = operation
do! Async.SwitchToContext context
return result
}

Resources