Thursday, August 18, 2011

Getting Started with the F# PowerPack - Part 2

In part 1 of this series, I provided a few links and examples of how to get started with the modules and types found in the math directory of the F# PowerPack. In this post, I'll do something similar with the command-line argument parser, AsyncOperations, AsyncStreamReader, and AsyncWorker.

ArgParser:

The F# PowerPack comes with a command-line parser that makes it easy to parse command-line options provided by a user.

The following links provide examples:

Example by Laurent Le Brun
Example by Robert Pickering
C# Port of Laurent Le Brun's Example by Steve Gilham

AsyncOperations:

Within the AsyncOperations.fsi file you'll find type extensions for StreamReader (AsyncReadToEnd) and File (AsyncOpenText, AsyncOpenRead, AsyncOpenWrite, AsyncAppendText, and AsyncOpen).

The following example is a modified version of one of the PowerPack unit tests, which shows AsyncOpenWrite and AsyncOpenRead in use.
open System.IO

async {
    async {
        let buffer = "F# is fun!"B
        use! is = File.AsyncOpenWrite "test.txt"
        do! is.AsyncWrite(buffer, 0, buffer.Length) 
        printfn "File written" } 
    |> Async.RunSynchronously

    async { 
        let buffer = Array.zeroCreate<byte>(7)
        use! is = File.AsyncOpenRead "test.txt"
        let! count = is.AsyncRead(buffer, 0, 7)
        printfn "File read"
        return count, buffer }
    |> Async.RunSynchronously |> ignore
} 
|> Async.Start

AsyncStreamReader:

The AsyncStreamReader type provides a simple approach to reading streams asynchronously. Here's an example:
open System
open System.IO
open System.Text

let text = [ new String([|for i in 1..1022 do yield 'x'|])
             new String([|for i in 1..1022 do yield 'y'|])
             new String([|for i in 1..1022 do yield 'z'|]) ].ToString()  

use stream = new MemoryStream()
stream.Write(Encoding.UTF8.GetBytes(text), 0, text.Length)
stream.Position <- 0L
let reader = new AsyncStreamReader(stream, Encoding.UTF8)          
async { let rec readAllChars () =
            async {
                let! eof = reader.EndOfStream
                if not eof then
                    let! character = reader.Read()
                    do printf "%s" (character.ToString())
                    return! readAllChars ()
                else 
                    printfn "%sRead complete" Environment.NewLine           
            }
        do! readAllChars ()
} 
|> Async.Start
Another example of AsyncStreamReader can be found here (see the answer provided by Brian McNamara).

AsyncWorker:

The AsyncWorker type provides a great way to define and launch a background worker. Don Syme shows how to create and use a similar type in his Async and Parallel Design Patterns in F#: Reporting Progress with Events (plus Twitter Sample) post.

Here's an example of the AsyncWorker type from the PowerPack.
open Microsoft.FSharp.Control

let rec job = async {   
        for i in 1 .. 20 do  
            printfn "doing some work"
            do! Async.Sleep 300
            worker.ReportProgress i
    }
    and worker : AsyncWorker<_> = AsyncWorker(job)

worker.ProgressChanged.Add(fun jobNumber -> printfn "job %d completed" jobNumber) 
worker.Error.Add(fun err -> printfn "Error: %A" err.Message)
worker.Completed.Add(fun _ -> printfn "All jobs have completed")
worker.Canceled.Add(fun _ -> printfn "Jobs have been canceled")

worker.RunAsync() |> ignore
Wrapping Up:

You can find working examples of each of these on my GitHub https://github.com/dmohl/FSharpPowerPackExample. Also, if you're interested in seeing more async examples, check out the series (C# Async Examples in F#) that Chris Marinos just started.

No comments:

Post a Comment