How to call and handle an Asynchronous F# Workflow from C#
I have read few F# tutorials and I have noticed how easy is to perform asynchronous and parallel programming in F# compared to C#. Thus, I am trying to write an F# library which will be called from C# and take take a C# function (delegate) as a parameter and run it asynchronously.
I have managed to pass the function so far (I am even able to cancel) but what I miss is how to implement a callback back to C# which will be executed it as soon as the asynchronous operation is completed. (e.g. the function AsynchronousTaskCompleted?). Also I was wondering if I can post (e.g. Progress %) back to F# from then function AsynchronousTask.
Can someone please help me?
This is the code I have written so far (I am not familiar with F# so the following code may be wrong or poorly implemented).
//C# Code Implementation (How I make the calls/handling)
//Action definition is: public delegate void Action();
Action action = new Action(AsynchronousTask);
Action cancelAction = new Action(AsynchronousTaskCancelled);
myAsyncUtility.StartTask2(action, cancelAction);
Debug.WriteLine("0. The task is in progress and current thread is not blocked");
......
private void AsynchronousTask()
{
//Perform a time-consuming task
Debug.WriteLine("1. Asynchronous task has started.");
System.Threading.Thread.Sleep(7000);
//Post progress back to F# progress window?
System.Threading.Thread.Sleep(2000);
}
private void AsynchronousTaskCompleted(IAsyncResult asyncResult)
{
Debug.WriteLine("2. The Asynchronous task has been completed - Event Raised");
}
private void AsynchronousTaskCancelled()
{
Debug.WriteLine("3. The Asynchronous task has been cancelled - Event Raised");
}
//F# Code Implementation
member x.StartTask2(action:Action, cancelAction:Action) =
async {
do! Async.FromBeginEnd(action.BeginInvoke, action.EndInvoke, cancelAction.Invoke)
}|> Async.S开发者_Go百科tartImmediate
do printfn "This code should run before the asynchronous operation is completed"
let progressWindow = new TaskProgressWindow()
progressWindow.Run() //This class(type in F#) shows a dialog with a cancel button
//When the cancel button is pressed I call Async.CancelDefaultToken()
member x.Cancel() =
Async.CancelDefaultToken()
To get the benefits of F# asynchronous workflow, you have to actually write the asynchronous computation in F#. The code you're trying to write will not work (i.e. it may run, but won't be useful).
When you're writing asynchronous computations in F#, you can make asynchronous calls using let!
and do!
. This allows you to use other primitive non-blocking computations. For example, you can use Async.Sleep
instead of Thread.Sleep
.
// This is a synchronous call that will block thread for 1 sec
async { do Thread.Sleep(1000)
someMoreStuff() }
// This is an asynchronous call that will not block threads - it will create
// a timer and when the timer elapses, it will call 'someMoreStuff'
async { do! Async.Sleep(1000)
someMoreStuff() }
You can only use asynchronous operations inside the async
block and it relies on the way how F# compiler handles do!
and let!
. There is no (easy) way to get real non-blocking execution for code that is written in sequential way (e.g. in C# or outside of async
block in F#).
If you want to use F# to get the benefits of asynchronous workflows, then the best option is to implement the operations in F# and then expose them to C# using Async.StartAsTask
(which gives you Task<T>
that C# can easily use). Something like this:
let someFunction(n) = async {
do! Async.Sleep(n)
Console.WriteLine("working")
do! Async.Sleep(n)
Console.WriteLine("done")
return 10 }
type AsyncStuff() =
member x.Foo(n) = someFunction(n) |> Async.StartAsTask
// In C#, you can write:
var as = new AsyncStuff()
as.Foo(1000).ContinueWith(op =>
// 'Value' will throw if there was an exception
Console.WriteLine(op.Value))
If you don't want to use F# (at least for the implementation of your async computations), then asynchronous workflows won't help you. You can implement similar thing using Task
, BackgroundWorker
or other C# technologies (but you'll loose the ability to run operations easily without blocking threads).
精彩评论