• Task.Run创建Task
  • 另一种方式就是用TaskCompletionSource来创建Task
  • TaskCompletionSource让你稍后开始和结束的任意操作中创建Task
    • 它会为你提供一个可手动执行的“从属”Task
      • 指示操作何时结束或发生故障
  • 它对IO-Bound类工作比较理想
    • 可以获得所有Task的好处(传播值、异常、Continuation等)
    • 不需要再操作的时候阻塞线程

使用TaskCompletionSource

  • 初始化一个实例即可
  • 它有一个Task属性可返回一个Task
  • 该Task完全由TaskCompletionSource对象控制
  • image.png
  • 调用任意一个方法都会给Task发信号:
    • 完成、故障、取消
  • 这些方法只能调用一次,如果再次调用:

    • SetXxx会抛出异常
    • TryXxx会返回false

      1. class Program
      2. {
      3. static void Main(string[] args)
      4. {
      5. var tcs = new TaskCompletionSource<int>();
      6. new Thread(() =>
      7. {
      8. Thread.Sleep(5000);
      9. tcs.SetResult(42);
      10. })
      11. {
      12. IsBackground = true
      13. }.Start();
      14. // 这行代码开始执行
      15. Task<int> task = tcs.Task;
      16. Console.WriteLine(task.Result);
      17. Console.ReadLine();
      18. }
      19. }
  • 自己实现类似于Task.Run方法

    1. class Program
    2. {
    3. static void Main(string[] args)
    4. {
    5. Task<int> task = Run(() =>
    6. {
    7. Thread.Sleep(5000);
    8. return 42;
    9. });
    10. Console.WriteLine(task.Result);
    11. }
    12. // 调用此方法相当于调用 Task.Factory.StartNew,
    13. // 并使用 TaskCreationOptions.LongRunning 选项来创建非线程池的线程
    14. static Task<TResult> Run<TResult>(Func<TResult> function)
    15. {
    16. var tcs = new TaskCompletionSource<TResult>();
    17. new Thread(() =>
    18. {
    19. try
    20. {
    21. tcs.SetResult(function());
    22. }
    23. catch (Exception e)
    24. {
    25. tcs.SetException(e);
    26. }
    27. }).Start();
    28. return tcs.Task;
    29. }
    30. }

TaskCompletionSource的真正魔力

  • 它创建Task,但并不占用线程

    1. public class Timer
    2. {
    3. static void Main(string[] args)
    4. {
    5. var awaiter = GetAnswerToLife().GetAwaiter();
    6. awaiter.OnCompleted(() =>
    7. {
    8. Console.WriteLine(awaiter.GetResult());
    9. });
    10. Console.ReadLine();
    11. }
    12. static Task<int> GetAnswerToLife()
    13. {
    14. var tcs = new TaskCompletionSource<int>();
    15. var timer = new System.Timers.Timer(5000) { AutoReset = false };
    16. timer.Elapsed += delegate
    17. {
    18. timer.Dispose();
    19. tcs.SetResult(42);
    20. };
    21. timer.Start();
    22. return tcs.Task;
    23. }
    24. }
    1. static void Main(string[] args)
    2. {
    3. Delay(5000).GetAwaiter().OnCompleted(() => Console.WriteLine(42));
    4. // 5秒钟之后,Continuation 开始的时候,才占用线程
    5. }
    6. // 注意:没有非泛型版本的 TaskCompletionSource
    7. static Task Delay(int milliseconds)
    8. {
    9. var tcs = new TaskCompletionSource<object>();
    10. var timer = new System.Timers.Timer(milliseconds) {AutoReset = false};
    11. timer.Elapsed += delegate
    12. {
    13. timer.Dispose();
    14. tcs.SetResult(null);
    15. };
    16. timer.Start();
    17. return tcs.Task;
    18. }
    19. }
  • Task.Delay相当于异步版本的Task.Sleep