为什么要有Task

.net 4.0之后

Task = Thread + ThreadPool + 优化和功能扩展

Task 是在ThreadPool的基础上进行的封装

Task的三种启动方式

  1. 实例化方式

    Task task = new Task(() =>
    {
      Console.WriteLine("我是工作线程: tid={0}", Thread.CurrentThread.ManagedThreadId);
    });
    ask.Start();
  2. TaskFactory的方式启动Task

    var task=Task.Factory.StartNew(() =>
    {
       Console.WriteLine("我是工作线程: tid={0}", Thread.CurrentThread.ManagedThreadId);
    });
  3. Task.Run 方法

    var task = Task.Run(() =>
    {
       Console.WriteLine("我是工作线程: tid={0}", Thread.CurrentThread.ManagedThreadId);
    });
  4. 同步执行

    var task = new Task(() =>
                        {
                            Console.WriteLine("我是工作线程: tid={0}", Thread.CurrentThread.ManagedThreadId);
                        });
    task.RunSynchronously();//同步执行,也就是阻塞执行

Task的返回值 Task

var task = new Task<string>(() =>
{
    return "Hello World!";
});
var result = task.Result;
Console.WriteLine(result);

Task的阻塞(返回值都是void)

  1. WaitAll方法 必须等待所有的task执行完成 &&的关系

  2. WaitAny方法,只要其中一个task执行完成就算完成

  3. task.Wait方法: 等待操作 类似thread.Join()

Task的延续

  1. WhenAll 在一组任务都完成后开始

  2. WhenAny 任何提供的任务已完成时,创建将完成的任务。

  3. Task工厂的延续操作,

    1. ContinueWhenAll 在一组任务都完成后开始
     Task.Factory.ContinueWhenAll(new Task[2] { task1, task2 }, (t) =>
     {
         //等待task1, task2都执行完成后再执行另一个线程的内容
         Console.WriteLine("我是主线程 {0}", DateTime.Now);
     });
    1. ContinueWhenAny 在提供组中的任何任务完成后开始

Task的一些枚举

一. TaskCreationOptions

public Task ContinueWith(Action<Task> continuationAction, TaskContinuationOptions continuationOptions);
Task task = new Task(() =>
{
    Task task1 = new Task(() =>
    {
        Thread.Sleep(100);
        Console.WriteLine("task1");
    }, TaskCreationOptions.AttachedToParent);
    Task task2 = new Task(() =>
    {
        Thread.Sleep(10);
        Console.WriteLine("task2");
    }, TaskCreationOptions.AttachedToParent);
    task1.Start();
    task2.Start();
});
task.Start();
task.Wait();  //task.WaitAll(task1,task2);
Console.WriteLine("我是主线程!!!!");
Console.Read();
  1. TaskCreationOptions.AttachedToParent将指定任务附加到任务层次结构中的某个父级,建立父子关系,父任务想要继续执行,必须等待子任务执行完毕
  2. TaskCreationOptions.DenyChildAttach 不让子任务附加到父任务上去。。。
  3. HideScheduler 子任务默认不使用父类的Task的Scheduler,而是使用默认的。
  4. LongRunning 长时间运行的任务,建议使用此选项
  5. PreferFairness ,类似一个Queue队列。以一种尽可能公平的方式安排任务,这意味着较早安排的任务将更可能较早运行,而较晚安排运行的任务将更可能较晚运行。

二. TaskContinuationOptions

  1. LazyCancellation 在延续取消的情况下,防止延续的完成直到完成先前的任务。需要等待task1执行完成之后再判断source.token的状态
  2. RunContinuationsAsynchronously 异步执行延续任务
  3. ExecuteSynchronously指定应同步执行延续任务.指定的线程也去用前面的线程,防止线程切换
  4. NotOnRanToCompletion,延续任务在前面的task没有完成的状态才执行
  5. OnlyOnRanToCompletion,延续任务在前面的task完成的状态才执行
  6. NotOnFaulted 前面的task没有抛出异常才执行。延续任务在前面的task没有未处理的异常时才执行
  7. OnlyOnFaulted 前面的task抛出异常才执行,延续任务在前面的task有未处理的异常时才执行
  8. NotOnCanceled 延续任务在前面的task没有取消时才执行
  9. OnlyOnCanceled 延续任务在前面的task已取消时才执行

Task的取消 CancellationTokenSource

  1. 当任务取消的时候,触发一个函数

    CancellationTokenSource source = new CancellationTokenSource();
    source.Token.Register(() =>//如果当前的token被取消,此函数将会被执行
    {
         Console.WriteLine("函数已执行");
    });
    var task = Task.Factory.StartNew(() =>
    {
        while (!source.IsCancellationRequested)
        {
            Thread.Sleep(100);
            Console.WriteLine("当前thread={0} 正在运行", Thread.CurrentThread.ManagedThreadId);
        }
    }, source.Token);
    Thread.Sleep(1000);
    source.Cancel();
  2. 延迟取消

    1. CancelAfter
    source.CancelAfter(new TimeSpan(0, 0, 0, 1));
    1. CancellationTokenSource 的构造函数中进行取消
    CancellationTokenSource source = new CancellationTokenSource(1000);
  3. 组合取消,其中任何一个CancellationTokenSource被取消,组合source也会被取消。。。

    CancellationTokenSource source1 = new CancellationTokenSource();
    CancellationTokenSource source2 = new CancellationTokenSource();
    source2.Cancel();
    var combineSource = CancellationTokenSource.CreateLinkedTokenSource(source1.Token, source2.Token);
  4. 任务取消后,抛出一个异常

    source.Token.ThrowIfCancellationRequested();

Task的返回值 Task

  1. Result 属性,通过Wait();获取,或者直接直接TResult,一样的效果

  2. ContinueWith

  3. Task.WhenAll或者 WhenAny

    var task = Task.WhenAll<int>(new Task<int>[2] { task1, task2 });
    var result = task.Result;//返回一个数组

Task的异常 AggregateException

AggregateException 是一个集合,因为task中可能会抛出多个异常,所以我们需要一种新的类型把这些异常都追加到一个

集合中

  1. 通过Wait操作, TResult操作获取异常

    try
    {
        task.Wait();
    }
    catch (AggregateException ex)
    {
        foreach (var item in ex.InnerExceptions)
        {
         Console.WriteLine(item.InnerException.Message);
        }
    }
  2. Handle方法遍历异常组

    处理当前的异常组,判断哪一层已经处理好了,没有处理好的,好需要向上抛

    ex.Handle(x =>
    {
         if (x.InnerException.Message == "我是 childTask1 异常")
     {
         return true;//继续向上抛
     }
     return false;
    });

并行编程模型--Task的一些封装Parallel

  1. For数组并行计算

    Parallel.For(0, 100, new ParallelOptions()
    {
        //设置所允许的并发任务的最大数目
        MaxDegreeOfParallelism = 10//设置多少个线程去执行
    }, (item, loop) =>
    {
        Console.WriteLine(item);
    });

    高级重载

    var totalNums = 0;
    Parallel.For<int>(1, 100, () => { return 0; }, (current, loop, total) =>
    {
        total += (int)current;
        return total;
    }, (total) =>
    {
        Interlocked.Add(ref totalNums, total);
    });
  2. ForEach 集合并行计算

    Parallel.ForEach(dic, (item) =>
    {
        Console.WriteLine(item.Key);
    });
  3. Invoke 并行计算多个函数

Pinq System.Linq.ParallelQuery

pinq底层都是基于task的编程模型,快速进行并行计算

划分区块,然后对区块进行聚合计算

  1. AsParallel 讲串行代码转换为并行
  2. AsOrdered 将结果进行未排序的样子进行排序
  3. AsUnordered 不按照原始顺序排序
  4. AsSequential 与AsParallel相对应,将plinq转换为linq
  5. WithDegreeOfParallelism 指定多少个线程并行
  6. WithCancellation 取消
  7. WithExecutionMode 是否强制并行

TaskSchedule

Task的核心就是Schedule,主要负责把任务安排在Thread或ThreadPool中

在.net framework中有两种TaskSchedele

  1. ThreadPoolTaskScheduler Task的默认调度形式,ThreadPool

  2. SynchronizationContextTaskScheduler,WinForm或WPF的多线程中,给一个控件赋值,都是调用Invoke

    var task = Task.Factory.StartNew(() =>
    {
        Thread.Sleep(1000 * 10);  //默认耗时操作
    });
    
    task.ContinueWith(t =>
    {
        label1.Text = "Hello Word!";
    }, TaskScheduler.FromCurrentSynchronizationContext());
  3. 自定义Schedule

    public class PerThreadTaskScheduler : TaskScheduler{}

async await

这两个关键词专用于处理文件IO,网络IO

  1. AsyncTaskMethodBuilder扮演了一个TaskComplationSource角色,就是Task包装器
  2. state:扮演者状态机状态的角色
  3. AwaitUnsafeOnCompleted 这个函数是丢给线程池去执行的,当某一时刻执行结束,会调用Movenext