C# Async Examples in F# – Part 3

This post is the third of a series where I am converting the C# 101 Async Samples into F#. See below for the other entries in the series:

C# Async Examples in F# – Part 1

C# Async Examples in F# – Part 2

The third async example deals with running operations in parallel. The C# version is structured similarly to the second example, but it starts the string downloads immediately instead of awaiting each result.

public async void AsyncIntroParallel()
{
    Task<string> page1 = new WebClient().DownloadStringTaskAsync(new Uri("http://www.weather.gov"));
    Task<string> page2 = new WebClient().DownloadStringTaskAsync(new Uri("http://www.weather.gov/climate/"));
    Task<string> page3 = new WebClient().DownloadStringTaskAsync(new Uri("http://www.weather.gov/rss/"));

    WriteLinePageTitle(await page1);
    WriteLinePageTitle(await page2);
    WriteLinePageTitle(await page3);
}

For the F# version, I changed things a bit from the last example to use a more functional style:

member this.AsyncIntroParallel = async {
    let read url = (new WebClient()).AsyncDownloadString(Uri(url))

    let! results = [ "http://www.weather.gov"; 
                     "http://www.weather.gov/climate/";
                     "http://www.weather.gov/rss/" ]
                   |> Seq.map read
                   |> Async.Parallel
    results
    |> Seq.iter this.WriteLinePageTitle
}

First, I construct an async workflow for each URL that performs the download. Next, I use the Async.Parallel combinator to tell the operations to start in parallel. Finally, I print the results in order using Seq.iter.

I mentioned this in Part 1, but this example really shows the difference in the way asynchronous operations are started between C# and F#. In C#, tasks are hot, so the three page requests occur immdeidately after the tasks are created. F# requires you to start async blocks by hand, but this gives you some additional flexiblity. Since the call to Async.Parallel at the end of the function is what triggers the parallelism, you can change that call to achieve different behavior while keeping the rest of the code the same. For example, if you want to switch back to synchronous behavior (perhaps for testing), you can do that as follows:

member this.AsyncIntroParallel = async {
    let read url = (new WebClient()).AsyncDownloadString(Uri(url))

    let results = [ "http://www.weather.gov"; 
                     "http://www.bing.com";
                     "http://www.google.com" ]
                  |> Seq.map read
                  |> Seq.map Async.RunSynchronously
    results
    |> Seq.iter this.WriteLinePageTitle
}

I prefer the flexibility and composability that the F# approach emphasizes. However, I like that C#’s hot starting behavior results in slightly less verbose code for simple examples.

This entry was posted in Async, C#, F#. Bookmark the permalink. Post a comment or leave a trackback: Trackback URL.

2 Trackbacks

  1. [...] C# Async Examples in F# – Part 3 [...]

  2. [...] C# Async Examples in F# – Part 3 [...]

Post a Comment

Your email is never published nor shared. Required fields are marked *

*
*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>