2

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.StartImmediate
        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()

1 Answer 1

8

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).

Sign up to request clarification or add additional context in comments.

6 Comments

The code seems to work fine but I am not sure if that's the way it should be implemented. If I write asynchronous computation in F# will I be able to use it from C#?
Thank for the reply, I will try familiarize myself with the Asynchronous computations.
@loannis: I added some information and example how you could write asynchronous workflow in F# & use it from C# using StartAsTask. Hope this will help!
Thank you for this question and answer! @Tomas, do you know if there is some way to consume F#'s Async type in C# as well, or would you generally recommend to make your F# code C# friendly, and not the other way around?
does Async.CancelDefaultToken() stop async{} computation expressions started with StartAsTask?
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.