Async workflows in F#

I thought I would share some more cool stuff regarding F#. I posted a little while ago a little preview of what is F# and how it works. I would like to go deeper here and cover a beautiful concept called asynchronous workflow.

To make it short, async workflows allows you to write asynchronous code, as if you would be writing synchronous code, but of course without blocking the UI thread.
Yeah, pretty cool :)

So generally, when it comes to asynchronous code, you immediately think about event handlers or callbacks. At least for most web developers. It is actually not really a problem today with most web programming languages like JS or AS3, cause there is no real support for concurrency/parallelism (for now). But imagine, if you had to use asynchronous calls in the context of multithreaded codeĀ in Java or C#. You could end up with a lot of handlers making your code hard to follow, complex to debug. Also, you will be very likely to share states introduce possible racing across threads. Finally, if you had to handle exceptions on top of all this, you would need to place exception handling almost everywhere.

So, this is why async workflows come to the rescue! :)

So, let's take a classic example. We have a list and we want to iterate over that list to grab the content of the URL, basically like URLStream would do in AS3:

let urlList = [ "Microsoft.com", "http://www.microsoft.com/"
                "MSDN", "http://msdn.microsoft.com/"
                "Bing", "http://www.bing.com"
              ]

Now let's define our fetch function which will do the job:

let fetch (name, url:string) =
    try
        printfn "Grabbing"
        let uri = new System.Uri(url)
        let webClient = new WebClient()
        let html = webClient.DownloadString(uri)
        printfn "Read %d characters for %s" html.Length name
    with
        | ex -> printfn "%s" (ex.Message)

We are basically grabbing the string from the URL, note that we are using here the synchronous API DownloadString.

Now, lets, iterate over our list and call the fetch function:

let runAll() =
    urlList
    |> List.map fetch
    |> ignore

If you remember the last post about F#, we use here the forward pipe operator that allows us to pass the result of a function to another in a very natural way. We simply map the fetch function on each element of our list

Ok, now, let's execute everything :

open System.Net
open Microsoft.FSharp.Control.WebExtensions

let urlList = [ "Microsoft.com", "http://www.microsoft.com/"
                "MSDN", "http://msdn.microsoft.com/"
                "Bing", "http://www.bing.com"
              ]

let fetch (name, url:string) =
    try
        printfn "Grabbing"
        let uri = new System.Uri(url)
        let webClient = new WebClient()
        let html = webClient.DownloadString(uri)
        printfn "Read %d characters for %s" html.Length name
    with
        | ex -> printfn "%s" (ex.Message)

let runAll() =
    urlList
    |> List.map fetch
    |> ignore

printfn "Starting"
runAll()
printfn "Done"

And here is the result :

Starting
Grabbing
Read 1020 characters for Microsoft.com
Grabbing
Read 35705 characters for MSDN
Grabbing
Read 30677 characters for Bing
Done

Ok, synchronous behavior, pretty simple, but actually pretty cool. Would be useful to have more synchronous APIs in Flash :)

Now, let's imagine we would like to make this asynchronous so that it does not block my UI, we would generally need to use an async API which would require the use of an event handler/callback. I actually don't want to do that, cause it would force me to change the structure of my code inside my fetch function, I want my syntax to remain linear and not have to jump somewhere else.

Good news, async workflows solve that:

let fetchAsync (name, url:string) =
    async {
        try
            printfn "Grabbing"
            let uri = new System.Uri(url)
            let webClient = new WebClient()
            let! html = webClient.AsyncDownloadString(uri)
            printfn "Read %d characters for %s" html.Length name
        with
            | ex -> printfn "%s" (ex.Message)
    }

Did you see the bang (!) character we used after the let for the html content? We call this the "bang" operator.

The effect of let! is to enable execution to continue on other computations or threads as the async operation is being performed. After the asynchronous call terminates, the rest of the asynchronous block code (asynchronous workflow) resumes its execution. Behind the scenes, when executed, the async block will create a new thread from the pool, execute the asynchronous operation and then the thread is released.

OK, so now let's apply this!

open System.Net
open Microsoft.FSharp.Control.WebExtensions

let urlList = [ "Microsoft.com", "http://www.microsoft.com/"
                "MSDN", "http://msdn.microsoft.com/"
                "Bing", "http://www.bing.com"
              ]

let fetchAsync (name, url:string) =
    async {
        try
            printfn "Grabbing"
            let uri = new System.Uri(url)
            let webClient = new WebClient()
            let! html = webClient.AsyncDownloadString(uri)
            printfn "Read %d characters for %s" html.Length name
        with
            | ex -> printfn "%s" (ex.Message)
    } |> Async.Start

let runAll() =
    urlList
    |> List.map fetchAsync
    |> ignore

printfn "Starting"
runAll()
printfn "Done"

Notice that we execute the async computation with the Async.Start call inside the fetchAsync function.

And here is the result:

Starting
Done
Grabbing
Grabbing
Grabbing
Read 1020 characters for Microsoft.com
Read 30677 characters for Bing
Read 35705 characters for MSDN

Sweet! Our code is now asynchronous, parallelized, and we retrieved the result of the asynchronous call in a synchronous fashion!

Simple, clean, efficient and safe :)

I hope you liked this intro to async workflows. Learn more about it here.