In C# awaiting the task awaiter is or ConfiguredTaskAwaitable is quite easy - just use await. What is the alternative for F#?
let! result = ...? doSomething().ConfigureAwait(false) ...?
F# async workflows and C# async-await keywords are two entirely separate mechanisms, and as such they are not directly compatible (though no doubt you can have wrappers that make that possible and most likely there are already wrappers like this around).
If you want to combine tasks with F# async workflow, you'd use the actual tasks rather than awaiters:
let! result = Async.AwaitTask task
If you have an API that gives you awaiters rather than tasks, here's a heavy-handed attempt at making an async out of a TaskAwaiter<'T>:
module Async =
let fromTaskAwaiter (awaiter: TaskAwaiter<'a>) =
async {
use handle = new SemaphoreSlim(0)
awaiter.OnCompleted(fun () -> ignore (handle.Release()))
let! _ = handle.AvailableWaitHandle |> Async.AwaitWaitHandle
return awaiter.GetResult()
}
Related
I want an async to wait for a value to be provided. C# has a mechanism for doing this in tasks, but I am using async.
Here is what I came up with:
type AsyncCompletionSource<'t>() =
let tcs = TaskCompletionSource<'t>()
with
member this.Set(x : 't) =
tcs.SetResult(x)
member this.Get
with get () =
Async.AwaitTask tcs.Task
I was wondering if there is something already provided for this in F#?
And if not, is there a way to accomplish this without jumping in and out of task?
Also called: future, promise, settable future, subject
let CreateEventSourcingConnection() =
task {
let connection =
let ipEndPoint = IPEndPoint(IPAddress.Loopback, 1113)
EventStoreConnection.Create(ipEndlPoint)
do! connection.ConnectAsync()
return connection
}
For task I get:
The value of constructor 'task' is not defined.
So, what is this and how can I define it?
I assume that the question is in the context of Logary, which gets the task computation builder from the TaskBuilder.fs NuGet package (as we can see from Paket references). The TaskBuilder.fs project is available here with some documentation.
So, task is a variable that represents an instance of the TaskBuilder computation builder. This is an F# computation expression, which lets you create computations that create the .NET Task<T> type as the result. Inside the computation expression, you can use let! and do! for the same purpose as await in C#, that is for waiting until some asynchronous operation completes (without blocking a thread):
task {
do! Console.Out.WriteLineAsync("Enter a filename:")
let! name = Console.In.ReadLineAsync()
use file = File.CreateText(name)
for i in Enumerable.Range(0, 100) do
do! file.WriteLineAsync(String.Format("hello {0}", i))
do! Console.Out.WriteLineAsync("Done")
return name
}
Here, WriteLineAsync and ReadLineAsync are .NET methods that return Task and we can use them as if they were returning just string or unit.
It is also worth adding that Logary is perhaps not the easiest piece of F# code to look into. It is very clever and nice, but relies on the HOPAC concurrency library which requires a fair bit of background knowledge and uses a number of fancy operators, which can make code quite tricky to understand. So if you are relatively new to F#, understanding HOPAC code might be a bit of a struggle!
I was wondering what would be the equivalent of the C# async main in F#. More to the point, is there a special way of consuming/using async methods from main in an F# program or is it just a matter of waiting for completion?
To be more concrete, say we are using the .NET Core Generic Host.
In a C# program, main might look like this:
class Program
{
static async Task Main(string[] args)
{
await new HostBuilder().Build().RunAsync();
}
}
In an F# program, my instinct would be to do something like this:
[<EntryPoint>]
let main args =
HostBuilder().Build.RunAsync().Wait()
...or...
[<EntryPoint>]
let main args =
HostBuilder().Build.RunAsync() |> Async.AwaitTask |> Async.RunSynchronously
...or...
[<EntryPoint>]
let main args =
async {
return HostBuilder().Build.RunAsync() |> Async.AwaitTask
} |> Async.RunSynchronously
...or just avoid async...but that's no fun...
[<EntryPoint>]
let main args =
HostBuilder().Build.Run()
There are a few more formulations I could show but I think these make the point.
I imagine that part of the answer lies in answering these other questions
"what does it mean to run an async main method" and
"what's the point of making main async?"
Going by examples, async main seems mostly to be about making it possible for other places to call main in an async way (in those cases where main is not really "main", ie. unit testing, etc).
In the case of F#, I imagine there are at least 2 things preventing one from just returning an Async computation from main:
The EntryPointAttribute that enforces an int return type for status codes...right?
The compiler probably is not prepared to handle the async computation as the exit value of the program...right?
AFAIK there's no async main equivalent in F#.
If you look at C# implementation behind the scenes it looks like this:
private static void <Main>(string[] args)
{
Program.Main(args).GetAwaiter().GetResult();
}
Program.Main is the async main.
Personally I find this pattern slightly scary depending on what SynchronizationContext is used.
To emulate async main I would:
let theAsyncTask : Async<int> = ...
[<EntryPoint>]
let main argv =
async {
do! Async.SwitchToThreadPool ()
return! theAsyncTask
} |> Async.RunSynchronously
theAsyncTask is the actual work to be done, the embedded async switches to the thread pool so that the main thread can safely block and await the result.
I'm converting the following C# code to F#. (https://github.com/confluentinc/confluent-kafka-dotnet/blob/master/examples/AvroGeneric/Program.cs)
var consumeTask = Task.Factory.StartNew(() =>
{
while (true)
{
consumer.Poll(100);
}
});
consumeTask.Wait();
Should it be replaced by Async workflow? BTW, is it a way not to use Poll?
For a more F#-idiomatic way of using Kafka in general, take a look at the Kafunk library from Jet.com. It has a nice F# API wrapping the Confluent .NET Kafka library, and in my experience it's also quite performant.
For TPL Tasks, you can use F# Async Workflows in much the same way:
let poller =
async {
while true do
consumer.Poll 100
}
poller |> Async.Start
If you want to use a Task inside your Async Workflow, you can use Async.AwaitTak, or you can blend them together using a custom workflow, like this one.
How do I use F#'s built-in support for async operations classes exposing the Event-based Asynchronous Pattern such as WebClient class?
let Download(url : Uri) =
let client = new WebClient()
let html = client.DownloadString(url)
html
When I try to change this to use "let!" in an async block (say as described in Soma's recent post)
let Download(url : Uri) =
async {
let client = new WebClient()
let! html = client.DownloadStringAsync(url)
return html }
I get an error message:
Type constraint mismatch. The type unit is not compatible with type Async<'a> The type 'unit' is not compatible with the type 'Async<'a>'
Edit: I'm really asking about the general question of using *Async() methods, WebClient is just an easy example. Microsoft says "... you should expose asynchronous features using the Event-based Asynchronous Pattern [ as opposed to BeginFoo()/EndFoo() ] whenever possible ..." so I would think there should be an easy way to consume an arbitrary *Async() method from F#.
The WebClient.DownloadStringAsync method is part of the .NET framework. It'll raise an event to signal its progress, and its return type is unit, so you don't want to use it, and there's no advantage in wrapping it in an async object.
The F# PowerPack defines an extension method, val webclient.AsyncDownloadString : uri -> Async{string}:
let Download(url : Uri) =
async {
let client = new WebClient()
client.Encoding <- Encoding.GetEncoding("utf-8")
let! html = client.AsyncDownloadString(url)
return html }
Unfortunately, the choice of name clashes with the existing webclient method, which can understandably cause confusion. However, I believe all of the F# async extensions begin with Async*.
[Edit to add in response to comments:]
Usually, .NET uses the BeginFoo / EndFoo pattern for concurrency. If the types are right, you can just use Async.BuildPrimitive beginMethod endMethod, which will return an Async wrapper for the method.
Sometimes objects don't use this pattern, like the WebClient, and you actually have to use Async.AwaitEvent to wait for an event to be fired, or write your own loop to repeatedly check to see if a bool is set. Here's a nice article on converting events to Async objects.
For what its worth, if you have F# installed, you should also have the source code which will give you an idea of how the F# team implements their async extensions. On my machine, the relevant file is located at:
C:\Program Files\FSharp-1.9.6.16\source\fsppack\FSharp.PowerPack\AsyncOperations.fs