Monthly Archives: May 2017

Asynchronous Child

Looking back at Running with Async we saw that you can run asynchronous workflows in multiple ways. We can use Async.RunSynchronously when we require the return value. We also looked at Async.Start when we don’t need a result. We also saw an example of running multiple asynchronous workflows using Async.Parallel. Let’s take a moment and get introduced to another means of starting asynchronous workflows.

Starting Children

We can use Async.StartChild when we want to evaluate an asynchronous workflow and get the result at a later time. This can be useful when aggregating data from multiple sources. Imagine having to hit multiple web servers or database servers to pull in data for analysis. We can start the workflows as children and get their results individually.

let getUrlContentSizeAsync (url : string) = 
    async {
        let request   = WebRequest.Create (url)
        use! response = request.AsyncGetResponse ()
        use stream    = response.GetResponseStream ()
        use reader    = new StreamReader(stream)
        let content   = reader.ReadToEnd() 
        do! Async.Sleep 500
        return (url,content.Length)
    }

let run1 = async {
        let! child = getUrlContentSizeAsync "http://techandwings.ca" 
                     |> Async.StartChild
        return! child
    }

run1 |> Async.RunSynchronously

In the function run1 we are using Async.StartChild to start the retrieving the content size for the URL. We are immediately returning the result from the child by using return!. Let’s add another URL.

let run2 = async {
        let! child1 = getUrlContentSizeAsync "http://techandwings.ca" 
                      |> Async.StartChild
        let! result1 = child1

        let! child2 = getUrlContentSizeAsync "http://nhl.com" 
                      |> Async.StartChild        
        let! result2 = child2

        return (result1, result2)
    }

run2 |> Async.RunSynchronously

When we start the run2 workflow we now receive a tuple containing the results of the two URLs we are retrieving. We start child1, wait for child1 to finish, start the child, and wait for its results. We’ve created our asynchronous workflow to retrieve the URL sizes sequentially. This is not an ideal use of the workflows. Let’s see if we can improve this by making a minor change.

let run3 = async {
        let! child1 = getUrlContentSizeAsync "http://techandwings.ca" 
                      |> Async.StartChild

        let! child2 = getUrlContentSizeAsync "http://nhl.com" 
                      |> Async.StartChild

        let! result1 = child1        
        let! result2 = child2

        return (result1, result2)
    }

run3 |> Async.RunSynchronously

Looking at run3 we can see we are starting the asynchronous workflows for both URLs before waiting for either result. The retrieval of the URLs’ sizes will happen concurrently. We then wait for the results of the child workflows and return them. This is a more effective use of Async.StartChild as we are now doing execution concurrently which can produce performance benefits when waiting for multiple long running IO operations.

If we enable #time in the REPL we should see a noticeable difference between run2 and run3. The difference is compounded by the Async.Sleep inserted in the getUrlContentSizeAsync function. You should see at least a half second speed up from run3 compared to run2.

Summary

Async.StartChild gives us the ability to control when start the asynchronous workflow and when we want the result. This in turn allows us to execute controlled asynchronous workflows concurrently. Executing asynchronous workflows as children is ideal for aggregating data from multiple sources.

Running with Async

Creating an asynchronous workflow doesn’t execute it immediately. It’s up to us to determine when and how we want the workflow to execute. So far we’ve been using Async.RunSynchronously to run our asynchronous workflow. By doing so, we are saying execute the async and wait for the result. This may not always be what we need. What if we want to write to a log file without blocking the current execution? We could use Async.Start.

Let’s revisit some code we looked at earlier. (Asyncing the F# Way)

let waiting () =
    async {
        printfn "Good night"
        do! Async.Sleep 2000
        printfn "Good morning"
    } |> Async.RunSynchronously
    printfn "Hello"

We get the expected results of:

Good night
Good morning
Hello

If we make a small change…

let nowaiting () =
    async {
        printfn "Good night"
        do! Async.Sleep 2000
        printfn "Good morning"
    } |> Async.Start
    printfn "Hello"

We’ve change the Async.RunSynchronously to Async.Start and our results are much different. We end up with results like this:

Hello
Good night
Good morning

(You’re results may be slightly different, however the “Hello” should always come before “Good morning”)

The reason Hello should always come before Good morning is we are no longer waiting for the result of the asynchronous expression. We are starting the asynchronous code and continuing on with the next expression.

Async.Parallel

We can use Async.Parallel when we have multiple asynchronous objects. This in turn can give some performance gains as multiple tasks are executed concurrently. We’ll use the getUrlContentsizeAsync and query some websites and sort them by size in descending order.

open System.IO
open System.Net

let getUrlContentSizeAsync (url : string) = 
    async {
        let request   = WebRequest.Create (url)
        use! response = request.AsyncGetResponse ()
        use stream    = response.GetResponseStream ()
        use reader    = new StreamReader(stream)
        let contents  = reader.ReadToEnd ()
        return (url,contents.Length)
    }

let sites = ["http://techandwings.ca"; 
             "http://www.cnn.com"; 
             "http://www.foxnews.com";
             "http://msnbc.com";
             "http://google.ca";
             "http://nhl.com";
             "http://mlb.com";
             "http://nfl.com"]

let asyncSites = sites |> List.map getUrlContentSizeAsync

In the REPL you can turn on some statistics analysis by entering the command:

#time;;

Let’s start by executing the list of asyncSites sequentially.

asyncSites |> List.map Async.RunSynchronously |> Seq.sortByDescending snd

The average results of running them sequentially a few times turned out to be around 4 seconds. (Your results may vary)

Real: 00:00:03.720, CPU: 00:00:00.869, GC gen0: 1, gen1: 0
val it : seq =
  seq
    [("http://nhl.com", 537569); ("http://mlb.com", 491099);
     ("http://nfl.com", 196920); ("http://www.cnn.com", 135159); ...]

If we make a couple of changes to the execution we should be able to speed it up. Let’s add Async.Parallel in exchange for the list map.

asyncSites |> Async.Parallel |> Async.RunSynchronously |> Seq.sortByDescending snd

The results of our new execution:

Real: 00:00:01.845, CPU: 00:00:00.820, GC gen0: 1, gen1: 0
val it : seq =
  seq
    [("http://nhl.com", 536551); ("http://mlb.com", 491099);
     ("http://nfl.com", 196920); ("http://www.cnn.com", 135159); ...]

My average results for running with Async.Parallel was just under 2 seconds. We’ve improved the performance of our experiment with a very minor change in how we are executing the asynchronous objects.

Summary

We’ve seen some new ways to run our asynchronous workflows. We have Async.RunSynchronous when we want to wait for the result. We can also start an asynchronous workflow without waiting for anything by using Async.Start. We’ve looked at the ability to chain multiple workflows into a list and execute them either sequentially or in parallel with the help of Async.Parallel. Running multiple asynchronous workflows in parallel can have some very drastic performance improvements. It’s always recommended to test and analyze any kind of enhancements to be sure. A very simple starting point for analysis is using the #time directive. Enabling #time will display some basic statistics about the code we are executing in the REPL.

Asyncing the F# Way

I recently gave a talk at the Winnipeg .Net User Group. This talk was focused on features of F# that are going to make their way into the world of C#. During the presentation I was talking about using local functions to wrap async functions. It was at this point someone asked if F# can do async/await. Well, the answer is yes.

The Async Builder

F# uses an Async Computation Expression for creating asynchronous workflows. The notation we use to denote an async computation is the async { ... }. Anything inside the curly braces are executed within the computation expression.

async {
    printfn "Good night"
    do! Async.Sleep 2000
    printfn "Good morning"
} |> Async.RunSynchronously

Looking at the example above, we have our async { ... } and our code within the curly braces. If you run the code in your REPL (Read Evaluate Print Loop) it will print “Good night”, wait 2 seconds, then print “Good morning”.

The Bang notation

The do! (do-bang) is our way of expressing we are evaluating an asynchronous expression. The do itself indicates we don’t care about the result. It’s the ! (bang) that the AsyncBuilder uses to unwrap the asynchronous expression’s result. It’s syntactic sugar to ensure our code is expressive and readable.

We use let! (let-bang) when we want to use the result of an asynchronous expression. In the doWorkAsync example below, we use the let! to bind the result of addAsync to the label result so we can print it.

let addAsync x y = async { return x + y }

let doWorkAsync = async {
    let! result = addAsync 4 6
    printfn "Result: %d" result
    }

Async.RunSynchronously doWorkAsync

Binding IDisposable

When we have an asynchronous expression which returns an object implementing IDisposable we should bind the result with use!. This unwraps the asynchronous expression, binds the disposable object, and disposes of the object when it falls out of scope. An example of use! is when retrieving the contents asynchronously from a website.

open System.IO
open System.Net

let getUrlContentSizeAsync (url : string) = 
    async {
        let request   = WebRequest.Create (url)
        use! response = request.AsyncGetResponse ()
        use stream    = response.GetResponseStream ()
        use reader    = new StreamReader(stream)
        let contents  = reader.ReadToEnd ()
        return (url,contents.Length)
    }

getUrl "http://techandwings.ca" |> Async.RunSynchronously

In the code above we are using the use! to unwrap the IDisposable response object. This in turn performs an automatic clean up when the object is no longer required.

Summary

We write asynchronous code in F# using the AsyncBuilder. The builder itself is syntactic sugar allowing us to write clean and expressive code. We use the Bang notation to unwrap the asynchronous calls within the builder. There are do!, let!, and use! to handle the results of an asynchronous expression. We’ve currently only looked at running the asynchronous code one way using the Async.RunSynchronously. We’ll look at more ways of running our code in a future post.