Hi I have a question about async in F#.
So I have a simple procedure that runs in background that is placed in a member of a type and it looks like:
type Sender() =
member this.Start(udpConectionPool) = async {
(* Some operation that continuously sends something over udp*)
} |> Async.Start
So this starts and begins to continuously sends frames over UDP without blocking rest of the program, but from time to time i want to restart thread (let us say i want to add new endpoint it would send it to that is udpConnectionPool parameter).
I was thinking about something like dumping task to member and then:
member this.Stop() = async {
do! (*stop async start member that contains task*)
}
And then I can restart this task with updated connection pool, but I don't know if I can do that.
My question is, Is it possible to stop such task, or if not is there a better way to do it?
The standard way of cancelling F# async workflows is using a CancellationToken. When you call Async.Start, you can provide a cancellation token. When the token gets cancelled, the async workflow will stop (after the current blocking work finishes):
open System.Threading
let cts = new CancellationTokenSource()
let work = async { (* ... *) }
Async.Start(work, cts.Token)
cts.Cancel() // Sometime later from another thread
To integrate this with the Sender, you could either store the current CancellationTokenSource and have a Stop method that cancels it (if you want to keep this inside a stateful class). Alternatively, you could return IDisposable from the Start method in a way that is similar to how the Observable interface work:
type Sender () =
member this.Start(udpConnectionPool) =
let cts = new CancellationTokenSource()
let work = async { (* ... *) }
Async.Start(work, cts.Token)
{ new System.IDisposable with
member x.Dispose() = cts.Cancel() }
This way, the caller of Start is responsible for storing the returned IDisposable and disposing of it before calling Start again.
Related
I'm publishing events to an Azure Event Hub with an F# script. The equivalent C# code is as follows:
var connectionString = "<< CONNECTION STRING FOR THE EVENT HUBS NAMESPACE >>";
var eventHubName = "<< NAME OF THE EVENT HUB >>";
await using (var producer = new EventHubProducerClient(connectionString, eventHubName))
{
using EventDataBatch eventBatch = await producer.CreateBatchAsync();
eventBatch.TryAdd(new EventData(new BinaryData("First")));
eventBatch.TryAdd(new EventData(new BinaryData("Second")));
await producer.SendAsync(eventBatch);
}
I don't think the following is the best idiomatic F# although it works:
let producerClient = EventHubProducerClient(connectionString, eventHubName)
let cancellationToken = CancellationToken()
let eventDataBatch =
cancellationToken
|> producerClient.CreateBatchAsync
let edb = eventDataBatch.Result
edb.TryAdd event
producerClient.SendAsync edb
note: I've not included the code to create the event but it's a JSON string.
How can I avoid the call to Result? This looks like a step that could be much cleaner.
You can rewrite code that uses C# async/await using the task { .. } computation expression in F#. Inside this, you can use let! in place of await, but also do! for awaiting tasks that do not return result and use! for awaiting IDisposable results.
I'm not sure what library are you using here, but something like this illustrates the syntax:
let connectionString = "<< CONNECTION STRING FOR THE EVENT HUBS NAMESPACE >>";
let eventHubName = "<< NAME OF THE EVENT HUB >>";
let processEvent() = task {
use producer = new EventHubProducerClient(connectionString, eventHubName)
use! eventBatch = producer.CreateBatchAsync()
eventBatch.TryAdd(EventData(new BinaryData("First")))
eventBatch.TryAdd(EventData(new BinaryData("Second")))
do! producer.SendAsync(eventBatch) }
If you then call processEvent(), the result will again be Task. You can ignore that (and let the computation run), or wait for the result of that, if you intend to block at the top level.
I have cases like the following:
async {
let! result = props.onClick args
do someThingLikeShowToastMessageWithResult(result)
return result
}
The async computation is not started by me, but by a library over which I have no control, and this library (correctly) passes in a cancellation tokent to the eventual StartImmediate call.
How could I write this async computation in a way that it is 'atomic'? eg if a containing async computation gets cancelled, it is either cancelled before this, or after this, but not inside this computation.
The intention behind this is that once the onClick async computation is called (which is a server call saving data) the data is sent over, and the server will save it bar other errors. Cancelling here will only result in cancelling the notification of the user that the server did what he told it to do.
Edit: the best I could figure out is to break the Async CE with some other construct (eg Task, or in this case Promise as this is in a Fable app):
async {
let ct = new System.Threading.CancellationTokenSource()
let computation =
async {
let! result = props.onClick args
do someThingLikeShowToastMessageWithResult(result)
return result
}
let atomicComputation =
Async.StartAsPromise(computation, token = ct.Token)
|> Async.AwaitPromise
return! atomicComputation
}
Seems pretty convoluted, and am not yet sure of all the unintended consequences.
I also can't think of a better approach, the only thing I would do is add some helper function to make your intent a little clearer.
module Async =
let runUncancellable a =
async {
let ct = new System.Threading.CancellationTokenSource()
return! Async.StartAsTask(a, cancellationToken = ct.Token) |> Async.AwaitTask
}
Usage:
let someAsyncOperation : Async<int> =
failwith "NYI"
async {
let! a = someAsyncOperation
let! b = runUncancellable someAsyncOperation
let! c = someAsyncOperation
return a + b + c
}
how to wait for the completion of Future without 'async' and 'futures'?
In the library that I use all functions are asynchronous.
// must return <bool>
bool my_func(int x){
//returns Future<int>
var tmp = somelib.somefunc( ... );
//wait y
return x == y;
}
I tried to write my 'await', but
waiting for a result with a while loop freezes everything.
dynamic my_await(Future f) {
dynamic x;
bool completed = false;
f.then((v){
x = v;
completed = true;
});
do {} while (!completed);
return x;
}
Dart VM version: 1.24.3 (Mon Dec 18 16:57:48 2017) on "linux_x64"
A synchronous function, or really, any Dart function, returns a value immediately when you call them. If you want to return a boolean immediately, and the value of that boolean depends on the result that some future completes with, then there is no way to compute that boolean in time.
If you need to wait for a future, then your function is asynchronous. You need to return something immediately, even if you don't know the result yet. That's what a Future is. It's not magical in any way, it's just an object that you can set a callback on which gets called when some result is ready.
So, you need to return a Future<bool> for this to work.
Dart is single-threaded. Without using isolates, there is no concurrency. Instead asynchronous functions work by taking turns, giving time for other code to run, e.g., while they wait on a future. If you just do a do {} while (!completed); then no other code gets to run, which means that nothing will be able to set completed to true.
I'm new to dart, so not sure if this is the correct way of doing it, but I've solved this issue by using the function whenCompleted() on the Future returned by the async method I'm calling.
Here openDatabase returns a Future.
abstract class IBaseDatabaseHandler {
Database sqliteDbHandler;
IBaseDatabaseHandler.sqlite(String dataBasePath) {
sqfliteFfiInit();
var databaseFactory = databaseFactoryFfi;
databaseFactory
.openDatabase(dataBasePath)
.whenComplete(() => sqliteDbHandler);
}
}
Let client be an instance of System.Net.Http.HttpClient.
In the following code
var response = await client.PostAsync(url, content);
processResponse(response);
there is no thread block between the first and the second line of code, so if we are in the UI thread, the UI remains responsive during the POST round-trip.
What is the F# code to obtain the same non-blocking behaviour? Is
let response = client.PostAsync(url, content) |> Async.AwaitTask |> Async.RunSynchronously
processResponse(response)
the correct code? I haven't clear whether RunSynchronously is blocking the current thread. If so, how do we obtain the same non-blocking behaviour as await?
EDIT
Maybe a little more context would help.
I have a Visual Studio solution with 2 projects: a WPF/WinForms app and a F# library, referenced by the app. The library provides a function/method, named FSLongWork(), which executes a long I/O operation, e.g. an HTTP GET or POST to a remote server using HttpClient.GetAsync/PostAsync, and returns a string.
The app front-end is a simple window with a button and a label. The button click handler must:
1) Call FSLongWork() in the F# library
2) Write in the Label a content that depends on the string returned in step 1.
Of course step 1 must occur asynchronously, to preserve UI responsiveness.
POSSIBLE C# app SOLUTION
F# library:
let FSLongWork() =
async {
do! Async.Sleep(5000);
return "F#"
} |> Async.StartAsTask
C# app click handler
private async void button1_Click(object sender, EventArgs e) {
var s = await FSLongWork();
label1.Text = s;
}
C# app button handler registration
this.button1.Click += new System.EventHandler(this.button1_Click);
POSSIBLE F# app SOLUTION
F# library:
let FSLongWork() =
async {
do! Async.Sleep(5000);
return "F#"
}
F# app click handler
let button1_Click (sender : obj) e =
async {
let! s = FSLongWork()
label1.Text <- s
}
F# app button handler registration
button1.Click.Add(RoutedEventHandler(fun sender e -> button1_Click sender e |> Async.StartImmediate)
The problem I see is that the F# library function (FSLongWork) is different in the two solutions (|> Async.StartAsTask is only in the first), which is not good in term of reusability.
We can use the first implementation in F# (change let! s = FSLongWork() to let! s = FSLongWork() |> Async.AwaitTask).
And the second implementation can be used in C# (change var s = await FSLongWork(); to var s2 = await Microsoft.FSharp.Control.FSharpAsync.StartAsTask(FSLongWork(), null, null);).
Yet it looks a bit awkward to me:
the natural F# implementation would be the second (without Async.StartAsTask), but this requires to reference Microsoft.FSharp and the use of the rather ugly Microsoft.FSharp.Control.FSharpAsync.StartAsTask(FSLongWork(), null, null); in the C# app.
On the other hand, the first implementation (with Async.StartAsTask), leads to a more natural use in C# (simply await FSLongWork()), but implies am async->Task->async round-trip when used by a F# app
Is there a way to write the F# library so that a C# user doesn't need to reference FSharp.Core and without influencing how the F# function is implemented?
see here: https://learn.microsoft.com/en-us/dotnet/fsharp/tutorials/asynchronous-and-concurrent-programming/async
Async.RunSynchronously will start an async workflow on another thread and await its result.
Async.Start will start an async workflow on another thread, and will not await its result.
So in this case:
async {
let! response = client.PostAsync(url, content) |> Async.AwaitTask
processResponse response
} |> Async.Start
In terms of good integration I would expect to be able to do as follows:
F# library:
let FSLongWork() =
async {
do! Async.Sleep(5000);
return "F#"
}
C# app click handler
private async void button1_Click(object sender, EventArgs e) {
var s = await FSLongWork();
label1.Text = s;
}
In other words, I would expect that the conversion between Async<> and Task<> was automatic/implicit when I use await in C#.
I thought that this was possible and that I wasn't able to find the way to do it, hence my questions.
Apparently, though, it is not possible and some manual conversion plumbing is required (as for example in the the possible solutions I reported).
Maybe it could be material for a future feature request.
I've written a Windows Service that periodically executes a SSIS package that moves documents from Server A to Server B.
The problem is that in order to do so, I need to use an infinite loop, which starts when the Service starts.
Naturally, I placed this loop into the OnStart() method. Unfortunately, the service never signals that it has started, since it never reaches the end of this method...
Here is the relevant code:
protected override void OnStart(string[] args)
{
Application app = new Application();
Package pkg = app.LoadFromDtsServer(#"MSDB\PullDoc", "Server", null);
while (true)
{
DTSExecResult pkgResults = pkg.Execute();//Execute the package.
EventLog.WriteEntry(pkgResults.ToString());
Thread.Sleep(1000 * 60 * 5);//Sleep at least five minutes.
}
}
I would imagine this is a common problem, given that most Services should be running indefinitely.
Any ideas on how to get this service to return that it has started?
Thanks!
You should use a System.Threading.Timer instead of an infinite loop.
Your service should do its work on a different thread. The OnStart, OnStop etc methods are there to process commands to your service from the Windows Service Control Manager (SCM), and the SCM expects them to return promptly.
Using a System.Threading.Timer as suggested by #SLaks achieves this: the timer events will be executed on a thread from the .NET Thread Pool. Your OnStart method just Enables the Timer, while the OnStop method disables it (OnPause and OnResume can do likewise if you want).
You are not doing this correctly, you should never block a function from returning and you should use a new Thread. As it was suggested, you should use a Timer object.
Here is a code snippet to show you how:
private void OnElapsedTime(object source, ElapsedEventArgs e)
{
CopyAToB();
}
Timer timer = new Timer();
protected override void OnStart(string[] args)
{
timer.Elapsed += new ElapsedEventHandler(OnElapsedTime);
timer.Interval = 60000 * 5;
timer.Enabled = true;
}
private void CopyAToB()
{
// do somethings
}
I would recommend that you use a System.Threading.Timer like suggested but here is an example of how I would implement the functionality.
In this example I have the function fire 4 times an hour and it will quickly validate if its still running from the previous call and if so skip it otherwise it will create a new thread and fire off the function.
Imports System.Threading
Public Class myService
Private myThreadingTimer As System.Threading.Timer
Private keepRunning As Boolean = False
Private processing As Boolean = False
Protected Overrides Sub OnStart(ByVal args() As String)
Dim myTimerCallback As New TimerCallback(AddressOf OnTimedEvent)
If YourCheckHere() Then
keepRunning = True
myThreadingTimer = New System.Threading.Timer(myTimerCallback, Nothing, 1000, 1000)
Else
'What you want to do here
End If
End Sub
Protected Overrides Sub OnStop()
keepRunning = False
End Sub
Private Sub OnTimedEvent(ByVal state As Object)
If Date.Now.Minute = 14 And Date.Now.Second = 31 Or Date.Now.Minute = 29 And Date.Now.Second = 31 _
Or Date.Now.Minute = 44 And Date.Now.Second = 31 Or Date.Now.Minute = 59 And Date.Now.Second = 31 _
Then
'Make Sure Its Supposed To Still Be Running
If keepRunning Then
'Make Sure The Process Is Not Already Running
If Not processing Then
'Process is not currently running lets start it
Dim myThread As New Thread(New ThreadStart(AddressOf myProcess))
myThread.Start()
End If
End If
End If
End Sub
Public Sub myProcess()
Try
' Set the processing flag so the function does not run again until complete
processing = True
'Do whatever logic you need here
Catch ex As Exception
'Since You Can Not Use A MessageBox Do Logging Or Whatever You Need Here
Finally
processing = False
End Try
End Sub
End Class