一、简介

  Task是.NET Framework4.0 TPL(任务并行库)提供的新的操作线程池线程的封装类。它提供等待、终止(取消)、返回值、完成通知、失败通知、控制执行的先后次序等优化线程操作功能。Task(任务)并不是线程,任务运行的时候需要使用线程,但并不是说任务取代了线程,任务代码是使用底层的线程(Thread或ThreadPool线程)运行的,任务与线程之间并没有一对一的关系。

二、Task创建与启动

  Task类创建的任务使用的是后台线程,所以在前台线程全部终止的时候,如果任务还没有全部执行完,就会被被动终止。创建一个新的任务时,任务调度器(默认是基于线程池的TaskScheduler调度器,ThreadPoolTaskScheduler)会找到一个最合适的工作者线程,然后将任务加入该工作者线程的本地队列(每个工作者线程都有对应本地队列),任务所包含的代码会在该线程中运行。

  

  先定义一个任务要执行的方法:

  

static void NewTask()
{
Console.WriteLine("开始一个任务");
Console.WriteLine("Task id:{0}",Task.CurrentId);
Console.WriteLine("任务执行完成");
}

  再创建和启动一个任务,有以下三种方式:

  1、使用TaskFactory创建一个任务

    TaskFactory tf = new TaskFactory();

    //任务就会立即启

    Task t1 = tf.StartNew(NewTask);

  2、使用Task类的Factory创建一个任务

    Task t2 = Task.Factory.StartNew(NewTask);

  3、Task构造函数并Start

    Task t3 = new Task(NewTask);

    t3.Start();

    Task t4 = new Task(NewTask, TaskCreationOptions.PreferFairness);

    t4.Start();

    //因为任务是后台线程,所以我们这里阻塞主线程一秒钟来等待任务全部执行完成

    Thread.Sleep(1000);

  注意:使用Task类的构造函数(第3种)和TaskFactory类的StartNew()方法(第2种)时,都可以传递TaskCreationOptions枚举中的值。TaskCreationOptions如下:

  

  注意:如果当前Task上的TaskCreationOptions设置为LongRunning的话,这个task就会委托到Thread中去执行,长时间运行的task占用着ThreadPool的线程,这时候ThreadPool为了保证线程充足,会再次开辟一些Thread,如果耗时任务此时释放了,会导致ThreadPool线程过多,上下文切换频繁,所以此时让Task在Thread中执行还是非常不错的选择,当然不指定这个LongRunning的话,就是在ThreadPool上执行。

三、Task状态与生命周期 

  任务Task有以下代表任务完成时状态的属性:

    1、IsCanceled,因为被取消而完成

    2、IsCompleted,成功完成

    3、IsFaulted,因为发生异常而完成

  任务并没有提供回调事件来通知完成(像BackgroundWorker一样),通过启用一个新任务的方式来完成类似的功能。 ContinueWith方法可以在一个任务完成的时候发起一个新任务,天然支持了任务的完成通知,可以在新任务中获取原任务的结果值。

四、Parallel

  使用Parallel.For、Parallel.ForEach的循环迭代的并行执行,TPL会在后台创建System.Threading.Tasks.Task的实例。使用Parallel.Invoke时,TPL也会创建与调用的委托数目一致的System.Threading.Tasks.Task的实例。

五、Task异常处理 

  当很多任务并行运行的时候,可能会并行发生很多异常。Task实例能够处理一组一组的异常,这些异常有System.AggregateException类处理。

class Program
{
private static ConcurrentQueue<Product> queue = null;
static void Main(string[] args)
{
queue = new ConcurrentQueue<Product>();
System.Threading.CancellationTokenSource token = new CancellationTokenSource();
Task tk1 = Task.Factory.StartNew(() => SetProduct(token.Token));
Thread.Sleep();
       //检查状态,是否因为异常而导致失败
if (tk1.IsFaulted)
{
//循环输出异常
foreach (Exception ex in tk1.Exception.InnerExceptions)
{
Console.WriteLine("tk1 Exception:{0}", ex.Message);
}
}
Console.ReadLine();
} static void SetProduct(System.Threading.CancellationToken ct)
{
for (int i = ; i < ; i++)
{
throw new Exception(string.Format("Exception Index {0}", i));
}
Console.WriteLine("SetProduct 执行完成");
}
}

六、Task取消

  通过取消标记来中断Task实例的执行。 CancellationTokenSource,CancellationToken下的IsCanceled属性标志当前是否已经被取消,取消任务,任务也不一定会马上取消。

class Program
{
private static ConcurrentQueue<Product> queue = null;
/* coder:释迦苦僧 */
static void Main(string[] args)
{
queue = new ConcurrentQueue<Product>();
System.Threading.CancellationTokenSource token = new CancellationTokenSource();
Task tk1 = Task.Factory.StartNew(() => SetProduct(token.Token));
Task tk2 = Task.Factory.StartNew(() => SetProduct(token.Token));
Thread.Sleep();
//取消任务操作
token.Cancel();
try
{
//等待完成
Task.WaitAll(new Task[] { tk1, tk2 });
}
catch (AggregateException ex)
{
//如果当前的任务正在被取消,那么还会抛出一个TaskCanceledException异常,这个异常包含在AggregateException异常中
Console.WriteLine("tk1 Canceled:{0}", tk1.IsCanceled);
Console.WriteLine("tk1 Canceled:{0}", tk2.IsCanceled);
} Thread.Sleep();
Console.WriteLine("tk1 Canceled:{0}", tk1.IsCanceled);
Console.WriteLine("tk1 Canceled:{0}", tk2.IsCanceled);
Console.ReadLine();
}
static void SetProduct(System.Threading.CancellationToken ct)
{
 //每一次循环迭代,都会有新的代码调用 ThrowIfCancellationRequested
//这行代码能够对 OpreationCanceledException 异常进行观察
//并且这个异常的标记与Task实例关联的那个标记进行比较,如果两者相同 ,而且IsCancelled属性为True,那么Task实例就知道存在一个要求取消的请求,并且会将状态转变为Canceled状态,中断任务执行。
//如果当前的任务正在被取消,那么还会抛出一个TaskCanceledException异常,这个异常包含在AggregateException异常中
//检查取消标记
ct.ThrowIfCancellationRequested();
for (int i = ; i < ; i++)
{
Product model = new Product();
model.Name = "Name" + i;
model.SellPrice = i;
model.Category = "Category" + i;
queue.Enqueue(model); ct.ThrowIfCancellationRequested();
}
Console.WriteLine("SetProduct 执行完成");
}
}
class Product
{
public string Name { get; set; }
public string Category { get; set; }
public int SellPrice { get; set; }
}

七、Task.WaitAll 并限定时长

  10毫秒没有完成任务,则输出了****

  queue = new ConcurrentQueue<Product>();
Task tk1 = new Task(() => { SetProduct(); SetProduct();});
Task tk2 = new Task(() => SetProduct());
tk1.Start();
tk2.Start(); //如果tk1 tk2 没能在10毫秒内完成 则输出 *****
if (!Task.WaitAll(new Task[] { tk1, tk2 }, ))
{
Console.WriteLine("******");
} Console.ReadLine();

八、Task返回值  Task<TResult>

 class Program
{ static void Main(string[] args)
{
Task<List<Product>> tk1 = Task<List<Product>>.Factory.StartNew(() => SetProduct());
Task.WaitAll(tk1);
Console.WriteLine(tk1.Result.Count);
Console.WriteLine(tk1.Result[].Name);
Console.ReadLine();
}
static List<Product> SetProduct()
{
List<Product> result = new List<Product>();
for (int i = ; i < ; i++)
{
Product model = new Product();
model.Name = "Name" + i;
model.SellPrice = i;
model.Category = "Category" + i;
result.Add(model);
}
Console.WriteLine("SetProduct 执行完成");
return result;
}
}

九、连续执行多个任务 ContinueWith

class Program
{ static void Main(string[] args)
{
//创建任务t1
Task t1 = Task.Factory.StartNew(() =>
{
Console.WriteLine("执行 t1 任务");
SpinWait.SpinUntil(() =>
{
return false;
}, ); });
//创建任务t2 t2任务的执行 依赖与t1任务的执行完成
Task t2 = t1.ContinueWith((t) =>
{
Console.WriteLine("执行 t2 任务");
SpinWait.SpinUntil(() =>
{
return false;
}, ); });
//创建任务t3 t3任务的执行 依赖与t2任务的执行完成
Task t3 = t2.ContinueWith((t) =>
{
Console.WriteLine("执行 t3 任务");
});
Console.ReadLine();
}
}

异步多线程 Task理解的更多相关文章

  1. .Net进阶系列(13)-异步多线程(Task和Parallel)(被替换)

    一. Task开启多线程的三种形式 1. 利用TaskFactory下的StartNew方法,向StartNew传递无参数的委托,或者是Action<object>委托. 2. 利用Tas ...

  2. .NET 异步多线程,Thread,ThreadPool,Task,Parallel,异常处理,线程取消

    今天记录一下异步多线程的进阶历史,以及简单的使用方法 主要还是以Task,Parallel为主,毕竟用的比较多的现在就是这些了,再往前去的,除非是老项目,不然真的应该是挺少了,大概有个概念,就当了解一 ...

  3. c#中@标志的作用 C#通过序列化实现深表复制 细说并发编程-TPL 大数据量下DataTable To List效率对比 【转载】C#工具类:实现文件操作File的工具类 异步多线程 Async .net 多线程 Thread ThreadPool Task .Net 反射学习

    c#中@标志的作用   参考微软官方文档-特殊字符@,地址 https://docs.microsoft.com/zh-cn/dotnet/csharp/language-reference/toke ...

  4. NET 异步多线程,THREAD,THREADPOOL,TASK,PARALLEL

    .NET 异步多线程,THREAD,THREADPOOL,TASK,PARALLEL,异常处理,线程取消 今天记录一下异步多线程的进阶历史,以及简单的使用方法 主要还是以Task,Parallel为主 ...

  5. .NET异步多线程,Thread,ThreadPool,Task,Parallel,异常处理,线程取消

    今天记录一下异步多线程的进阶历史,以及简单的使用方法 主要还是以Task,Parallel为主,毕竟用的比较多的现在就是这些了,再往前去的,除非是老项目,不然真的应该是挺少了,大概有个概念,就当了解一 ...

  6. 异步多线程 Thread ThreadPool Task

    一.线程 Thread ThreadPool 线程是Windows任务调度的最小单位,线程是程序中的一个执行流,每个线程都有自己的专有寄存器(栈指针.程序计数器等),但代码区是共享的,即不同的线程可以 ...

  7. Task/Parallel实现异步多线程

    代码: #region Task 异步多线程,Task是基于ThreadPool实现的 { //TestClass testClass = new TestClass(); //Action<o ...

  8. 初探.net framework 下的异步多线程

    初探.net framework 下的异步多线程 目录 1.多线程的出现条件 2.Thread和ThreadPool的相关Api及用法 3.Task和Parallel的相关Api及用法 4.Async ...

  9. 基于任务的异步编程(Task,async,await)

    这节讲一下比较高级的异步编程用法Task,以及两个异步关键字async和await. Task是在C#5.0推出的语法,它是基于任务的异步编程语法,是对Thread的升级,也提供了很多API,先看一下 ...

随机推荐

  1. linux查看文件被哪个进程占用?

    1> 如果文件是端口号 netstat -ntlp | grep portNum [root@localhost root]# netstat -ntlp Active Internet con ...

  2. [Centos] ERROR: Could not find useradd in chroot, maybe the install failed?

    [mockbuild at localhost ~]$ mock -r centos-5-x86_64-testdev.cfg initinitcleanprepThis may take a whi ...

  3. iOS 用其他应用程序打开文件功能

    先摘抄一段我抄别人用的. <key>CFBundleDocumentTypes</key>    <array>        <dict>       ...

  4. UI设计教程分享:6个不能错过的UI设计网站

    Ui设计学习的人越来越多了,想要找到合适的学习资料很难,很多才接触ui设计且没有基础的同学也不知道去哪里找学习资料,虽然现在百度上很容易搜到ui设计的学习资料,但是一看不难发现,很多都是过时的学习资料 ...

  5. Eclipse 安装使用 M2Eclipse 插件

    help --> Install New Software --> Add 安装完后需要重启eclipse 通常 Eclipse 会自带 Maven.但可能按自己安装的 Maven 存在版 ...

  6. Intellij idea 系列教程之常用配置项

    Intellij idea 系列教程之常用配置项 Intellij idea 系列教程目录(https://www.cnblogs.com/binarylei/p/10347600.html) Lan ...

  7. RunAsPolicy Exit Code 1替代

    <Policies>  <RunAsPolicy CodePackageRef="Code" UserRef="SetupLocalSystem&quo ...

  8. qr 生成二维码

    package com.common; import com.swetake.util.Qrcode; import jp.sourceforge.qrcode.QRCodeDecoder; impo ...

  9. 二叉搜索树(BST)

    二叉搜索树需满足以下四个条件: 1.若任意节点的左子树不空,则左子树上所有结点的值均小于它的根结点的值: 2.若任意节点的右子树不空,则右子树上所有结点的值均大于它的根结点的值: 3.任意节点的左.右 ...

  10. 纯css导航栏下划线

    .nav-underline > *{/* 指定容器,里面可以是li.span等多样化的元素 */ display: inline-block; margin: -3px; padding: 1 ...