All together now!

I have just finished reading two academic papers connected to F#. The first is an academic paper on the async tasking model which has been in F# for several years. The async model makes it easy to use lightweight tasks via the computational workflows that F# has built into the language. These make it easy to express algorithms that require a set of steps that need to wait for some external stimulus between the steps. For the rest of this post, we’ll use the example:

> let task =
–   async {
–     do printfn “part 1”
–     do! Async.Sleep 1000
–     do printfn “part 2”
–     do! Async.Sleep 1000
–     do printfn “part 3”
–     };;

val task : Async<unit>

This task prints a message, and then sleeps for second using a function that the Async library makes available. This function finishes the current action, potentially allowing the current thread to be released, with a new thread later being allocated to carry out the next step when the wait has finished. We are using the Sleep here to simulate something like an I/O action which might take a long time and where we don’t want a thread to be allocated while this wait is happening (for scalability reasons).

The paper discusses some interesting aspects of the design. For example, why Async is implemented as a task factory and not as a constructor for a hot or cold task, and also how cancellation is handled by the model – essentially tasks pass around cancellation tokens, which are polled at regular intervals to see if the current action should be aborted.

Another interesting aspect, and one that is often missed out, is that SynchronizationContexts are captured at the appropriate points and are used to ensure that the actions are carried out on the right thread. It is quite instructive to see this in action.

First, we’ll define our own SynchronizationContext. This will only support the Post method which is used to move a callback into the correct context for its execution. Our SynchronizationContext will actually do its work on the threadpool, and will need to set the context of the threadpool thread which is allocated to it to ensure that when the next step executes the context is passed on correctly.

> open System.Threading;;
> type MyContext() =
–   inherit SynchronizationContext()
–   override this.Post (callback, state) =
–     printfn “Posted!”
–     let _ =
–       ThreadPool.QueueUserWorkItem (
–         WaitCallback (
–           fun _ ->
–             let _ = SynchronizationContext.SetSynchronizationContext this
–             callback.Invoke(state)))
–     ();;

We can build an instance of this type
> let myContext = MyContext();;

And then we can start the Async running inside this context. The “Posted!” output strings show the work items coming back into our context when they are available for running.

> let _ = SynchronizationContext.SetSynchronizationContext myContext
– Async.StartImmediate task;;
part 1
> Posted!
part 2
part 3

You may of course worry that setting the context on the Threadpool thread has had a lasting effect, but it’s easy to check by running some code which uses Threadpool threads, that this one of the thread properties that gets reset before the next work item is taken off the ThreadPool work queue.

Computational workflows are a really nice feature of F#. The language contains a small amount of syntax which is de-sugared by the compiler which uses methods of a builder object to produce the final result. For example, the workflow above
   async { …. }
uses the methods on the pre-built instance of AsyncBuilder.

> async;;
val it : AsyncBuilder = Microsoft.FSharp.Control.FSharpAsyncBuilder

The second paper takes this idea of syntactic language extensions and applies them to pattern matching. These joinads can be used to pattern match over libraries like the joins library, allowing the matching to be expressed concisely within the context of a workflow using the match! operation. These new patterns get translated into code using another set of methods of a builder object, making the whole mechanism nice and extensible. It will be interesting to see when this new functionality makes its way into the F# language.

This entry was posted in Computers and Internet. Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s