.Net Async Programming - Part 2

In the first article in the series I covered the programming with a single thread, in this article I will cover how to call blocking method in our one thread without blocking our single thread.

In order to write completely async code with a single thread we need to make sure that the one thread we have will always do work and not block on IO operation (disk, network, database, etc…).
Some IO classes on .net have async pattern implementation, in the next article we will see how to use them as well.

Let’s that when a deposit is made we want to save it to DB, so we have a repository with the insert method and when the Deposit method is being called we will insert it to the DB:

public Task Deposit(double amount)  
{
  Task task = new Task(() =>
    {
      m_balance += amount;

      m_depositRepository.Insert(AccountId, amount);
    });
  task.Start(m_taskScheduler);

  return task;
}

We took the example from the last post and just added the insert call, the problem with this code is that our single thread will block on the Insert call until the insert is complete, deny other tasks from being processed. To solve this we are going to schedule the Insert call on a thread pool thread:

public Task Deposit(double amount)  
{
  Task task = new Task(() =>
    {
      m_balance += amount;

      Task.Factory.StartNew(
        () => m_depositRepository.Insert(AccountId, amount));
    });
  task.Start(m_taskScheduler);

  return task;
}

Now the single thread won’t be blocked, but there is a still a problem with this code because the Deposit method might return before the insert is actually completed, compromise the integrity of our code and software, let’s try to solve this using .Net 4.0:

public Task Deposit(double amount)  
{
  TaskCompletionSource<int> taskCompletionSource = 
    new TaskCompletionSource<int>();

  Task task = new Task(() =>
    {
      m_balance += amount;

      Task.Factory.StartNew(
        () => m_depositRepository.Insert(AccountId, amount)).ContinueWith(
          () => taskCompletionSource.SetResult(1));
    });
  task.Start(m_taskScheduler);

  return taskCompletionSource.Task;
}

We are using a task completion source (we are using int because there is no void task completion source, yes it is ugly) to signal when the insert is actually completed.
The problem with this code is that it’s not so elegant and contain too much boilerplate code, with .Net 4.5 this become much easier:

public async Task Deposit(double amount)  
{
  Task task = new Task(() =>
  {
    m_balance += amount;

    await Task.Factory.StartNew(
      () => m_depositRepository.Insert(AccountId, amount));
  });
  task.Start();

  await task;
}

Summary

Using the thread pool is for the example but if our system is handling a lot of requests we can exhaust the thread pool with the blocking operations, the better approach will be to use the Async Pattern of .Net, we will see an example in our next article in the series.

Another thing worth mentioning, when writing a single thread code the gate (the place we transition into our thread) will not actually be in our business objects as in our example, I’m only doing it there for sake of the example, it will probably be in higher layers (application layer, infrastructure of the facade, depend on your system architecture), I will discuss this in future article in the series.

comments powered by Disqus