The bot framework uses C# async, await, Task, etc. So I took this opportunity and revisited TPL.

My previous knowledge of TPL was from .net 4.0. It has been a while. So I did a warm up exercise. The source code is at the end of this blog.

When I ran the program, the control flow looked like:

  1. The main thread began
  2. The main thread kicked off task threads, and suspend. (UI screen unresponsive if you have UI). The task threads began, and finished one by one.
  3. The task threads waited for each other until all were done before transferred the control back to the main thread.
  4. The main thread ended

The reuse of threads from thread pools:

  1. If you let the threads slept short periods of time (simulating light workload), you will see there are only 3-4 worker threads running. The tasks reused threads from the pool
  2. If you let the threads slept longer periods of times (simulating heavy workload), you will see each task use its own thread.

 

References

TPL

Task

TaskFactory.StartNew

Task.WaitAll

 

Exercise

        
public class TPLDemo {
  public static void DemoRun() {
    Func<object, int> action = (object obj) => {
      int result = 0; // 0: fail, 1: success
      int workerNumber = (int) obj;

      try {
        // If you let the current thread sleep workNumber % 3 * 2000 s, 
        // you will see there are only 3-4 worker threads running
        int msSleep = workerNumber % 3 * 2000; 
        // If you let the current thread sleep 10s, 
        // you will see there are 10 worker threads running
        // int msSleep = 10000; 
        Console.WriteLine("Worker #" + workerNumber + ", ThreadId: " 
          + Thread.CurrentThread.ManagedThreadId 
          + ", begin to process tons of data here ... " + msSleep + " ms.");
        Thread.Sleep(msSleep);
        Console.WriteLine("Worker #" + workerNumber + ", ThreadId: " 
          + Thread.CurrentThread.ManagedThreadId + ", end");

        result = 1;
      } catch (Exception exc) {
        System.Console.WriteLine(exc.Message + ", " + exc.StackTrace);
      }

      return result;
    };

    int size = 10;
    Task[] tasks = new Task [size];
    for (int i = 0; i < size; i++) {
      tasks[i] = Task.Factory.StartNew(action, (i + 1));
    }

    try {
      Task.WaitAll(tasks);
      int sum = 0;
      for (int i = 0; i < size; i++) {
        sum += tasks[i].Result;
      }
      Console.WriteLine(sum);
    } catch (AggregateException e) {
      for (int j = 0; j < e.InnerExceptions.Count; j++)
        System.Console.WriteLine(e.InnerExceptions[j]);
        System.Console.WriteLine(e.Message + ", " + e.StackTrace);
      }
    }
}        
Advertisements