October 11, 2007

Dream Asynchronicity Timers

Steve Bjorg @ 4:30 pm

Among the many challenges of building reliable, asynchronous applications is the issue of timeouts. In the asynchronous world, there is no difference between an operation that never completes and one that simply takes a very long time. So, the application must enforce a time limit for how long it is willing to wait. However, here is the catch: most timeouts are for naught since under normal conditions operations complete and don’t timeout!

In MindTouch Dream we reinvented the .NET timer object to suit this need. The TaskTimer class is a lightweight timer that uses techniques from generational garbage collectors to avoid unnecessary overhead.

You create a new TaskTimer like this:

TaskTimer timer = new TaskTimer(delegate(TaskTimer t) {
    Console.WriteLine("Timer triggered!");
});

You then give your timer a TimeSpan or DateTime value for when it should trigger:

timer.Change(TimeSpan.FromMinutes(5));

This timer will trigger in 5 minutes, unless you tell it to stop by changing its trigger time again:

timer.Change(DateTime.MaxValue);

This code should look familiar as this is very similar to how the built-in .NET timer works.

Here is what is different. When the timer is started, it isn’t actually activated. Instead, it is placed into a hash-table to wait for activation. Activating and deactivating a timer is expensive as it entails placing the timer into the proper order compared to its peers, as well as finding it again when it needs to be deactivated.

By placing it into a hash-table rather than a priority queue, we can drastically reduce the overhead as operating on hash-table is a lot more efficient. The timer will quietly live there, unactivated, until its time draws near. At that point it will be moved from the hash-table to the priority queue.

Of course, the question is: if the timer isn’t active, how does it know its time is coming near? Simple. The implementation scans the list of inactive timers every 30 seconds and promotes timers into the priority queue if they will trigger in 60 seconds or less. The linear scan is very fast and is nicely amortized over the many timer creations and destructions. Since we’re trying to optimize the most common case, this is a good trade-off.

This approach of classifying timers into two categories — pending and queued — minimizes runtime overhead considerably. So, now that we have cheap timers, we can make sure that we use them everywhere to ensure reliable, asynchronous operations. When you use the Result or Result<T> classes, you are already using implicitly the TaskTimer class. When the timer triggers, a TimeoutException will be thrown allowing you to clean-up resources and recover from the error.

To create a Result instance with a custom timeout value, just specify it in the constructor:

Result r = new Result(TimeSpan.FromSeconds(30));

The default timeout value is 10 minutes. To suppress the timeout, pass in TimeSpan.Max instead.

By implicitly using the timer, we added some overhead to Dream, but we also moved the responsibility from the developer to the framework. And that should make all our lives a little bit easier! ;)
Addendum: some will likely frown at using a hash-table for pending timers, and they would be right. A better data structure would be a lock-free, double-linked list. Unfortunately, I wasn’t able to find a proven implementation. A lock-free data structure would be perfect for pending timers as the current use of the hash-table implies a global lock, which is not optimal. If anyone knows of a reliable lock-free, double-linked list for C# or is up for the challenge, please let me know!

1 Comment »

  1. [...] previous posts (here and here), I introduced the building blocks for asynchronous programming in MindTouch Dream. In [...]

    Pingback by Dream Asynchronicity Library | MindTouch Blog — November 24, 2007 @ 12:50 pm

RSS feed for comments on this post. TrackBack URL

Leave a comment