C# - Task(任务)和Thread(线程)的区别
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C# - Task(任务)和Thread(线程)的区别相关的知识,希望对你有一定的参考价值。
参考技术A 本文介绍了任务和线程的定义和使用,以及两者之前的差别:什么是任务 - Task?
什么是线程 - Thread?
我们为什么需要任务?
为什么我们需要线程?
如何实现任务
如何实现线程
任务和线程之间的差异
.NET框架提供Threading.Tasks类,这样可以创建任务并 异步 运行它们。 任务是代表应该完成的某些工作的对象。 该任务可以告诉您工作是否完成,并且操作返回结果,则任务将为您提供结果。
.NET Framework在System.Threading命名空间中具有与线程相关的类。 线程是一小组可执行指令。
每当您要 并行 执行某些操作时都可以使用它。 使用“async”和“await”关键字在任务中实现异步很容易。
需要应用程序同时执行几个任务的时候。
static void Main(string[] args)
Task < string > obTask = Task.Run(() => (
return “ Hello”));
Console.WriteLine(obTask.result);
static void Main(string[] args)
Thread thread = new Thread( new ThreadStart(getMyName));
thread.Start();
public void getMyName()
Thread类用于在Windows中创建和操作线程。 任务代表某种异步操作,并且是任务并行库的一部分,任务并行库是一组用于异步和并行运行任务的API。
该任务可以返回结果。 没有直接的机制可以从线程返回结果。
一个任务可以同时发生多个进程。 线程一次只能运行一个任务。
使用“async”和“await”关键字轻松实现异步。
新的Thread()不处理线程池线程,而Task确实使用线程池线程。
任务是比线程更高层次的概念。
class Program
private static string result;
static void Main()
SaySomething();
Console.WriteLine(result);
static async TaskSaySomething()
awaitTask.Delay(5);
result = "Hello world!";
return “Something”;
如果Task.Delay(5)被Thread.Sleep(5)替代,那么输出有什么不同?为什么?
如果使用Task.Delay(5),输出内容为空,因为使用该方法,进行异步运行,任务要求等待5毫秒才能继续运行进而返回内容,但是5毫秒的等待时,主程序已经调用输出方法了。
如果使用Thread.Sleep(5),内容应该是Something因为该方法让运行的线程停止5毫秒,然后继续执行程序。
认识Task和Task的基本使用(转)
对于多线程,我们经常使用的是Thread。在我们了解Task之前,如果我们要使用多核的功能可能就会自己来开线程,然而这种线程模型在.net 4.0之后被一种称为基于“任务的编程模型”所冲击,因为task会比thread具有更小的性能开销,不过大家肯定会有疑惑,任务和线程到底有什么区别呢?
任务和线程的区别:
1、任务是架构在线程之上的,也就是说任务最终还是要抛给线程去执行。
2、任务跟线程不是一对一的关系,比如开10个任务并不是说会开10个线程,这一点任务有点类似线程池,但是任务相比线程池有很小的开销和精确的控制。
1、认识Task
首先来看一下Task的继承结构。Task标识一个异步操作。
可以看到Task和Thread一样,位于System.Threading命名空间下,这也就是说他们直接有密不可分的联系。下面我们来仔细看一下吧!
2、创建Task
创建Task的方法有两种,一种是直接创建——new一个出来,一种是通过工厂创建。下面来看一下这两种创建方法:
//第一种创建方式,直接实例化 var task1 = new Task(() => { //TODO you code });
这是最简单的创建方法,可以看到其构造函数是一个Action,其构造函数有如下几种,比较常用的是前两种。
//第二种创建方式,工厂创建 var task2 = Task.Factory.StartNew(() => { //TODO you code });
这种方式通过静态工厂,创建以个Task并运行。下面我们来建一个控制台项目,演示一下,代码如下:
要添加System.Threading.Tasks命名控件引用。
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace TaskDemo { class Program { static void Main(string[] args) { var task1 = new Task(() => { Console.WriteLine("Hello,task"); }); task1.Start(); var task2 = Task.Factory.StartNew(() => { Console.WriteLine("Hello,task started by task factory"); }); Console.Read(); } } }
这里我分别用两种方式创建两个task,并让他们运行。可以看到通过构造函数创建的task,必须手动Start,而通过工厂创建的Task直接就启动了。
下面我们来看一下Task的声明周期,编写如下代码:
var task1 = new Task(() => { Console.WriteLine("Begin"); System.Threading.Thread.Sleep(2000); Console.WriteLine("Finish"); }); Console.WriteLine("Before start:" + task1.Status); task1.Start(); Console.WriteLine("After start:" + task1.Status); task1.Wait(); Console.WriteLine("After Finish:" + task1.Status); Console.Read();
task1.Status就是输出task的当前状态,其输出结果如下:
可以看到调用Start前的状态是Created,然后等待分配线程去执行,到最后执行完成。
从我们可以得出Task的简略生命周期:
Created:表示默认初始化任务,但是“工厂创建的”实例直接跳过。
WaitingToRun: 这种状态表示等待任务调度器分配线程给任务执行。
RanToCompletion:任务执行完毕。
Task最吸引人的地方就是他的任务控制了,你可以很好的控制task的执行顺序,让多个task有序的工作。下面来详细说一下:
1、Task.Wait
在上个例子中,我们已经使用过了,task1.Wait();就是等待任务执行完成,我们可以看到最后task1的状态变为Completed。
2、Task.WaitAll
看字面意思就知道,就是等待所有的任务都执行完成,下面我们来写一段代码演示一下:
static void Main(string[] args) { var task1 = new Task(() => { Console.WriteLine("Task 1 Begin"); System.Threading.Thread.Sleep(2000); Console.WriteLine("Task 1 Finish"); }); var task2 = new Task(() => { Console.WriteLine("Task 2 Begin"); System.Threading.Thread.Sleep(3000); Console.WriteLine("Task 2 Finish"); }); task1.Start(); task2.Start(); Task.WaitAll(task1, task2); Console.WriteLine("All task finished!"); Console.Read(); }
其输出结果如下:
可以看到,任务一和任务二都完成以后,才输出All task finished!
3、Task.WaitAny
这个用发同Task.WaitAll,就是等待任何一个任务完成就继续向下执行,将上面的代码WaitAll替换为WaitAny,输出结果如下:
4、Task.ContinueWith
就是在第一个Task完成后自动启动下一个Task,实现Task的延续,下面我们来看下他的用法,编写如下代码:
static void Main(string[] args) { var task1 = new Task(() => { Console.WriteLine("Task 1 Begin"); System.Threading.Thread.Sleep(2000); Console.WriteLine("Task 1 Finish"); }); var task2 = new Task(() => { Console.WriteLine("Task 2 Begin"); System.Threading.Thread.Sleep(3000); Console.WriteLine("Task 2 Finish"); }); task1.Start(); task2.Start(); var result = task1.ContinueWith<string>(task => { Console.WriteLine("task1 finished!"); return "This is task result!"; }); Console.WriteLine(result.Result.ToString()); Console.Read(); }
执行结果如下:
可以看到,task1完成之后,开始执行后面的内容,并且这里我们取得task的返回值。
在每次调用ContinueWith方法时,每次会把上次Task的引用传入进来,以便检测上次Task的状态,比如我们可以使用上次Task的Result属性来获取返回值。我们还可以这么写:
var SendFeedBackTask = Task.Factory.StartNew(() => { Console.WriteLine("Get some Data!"); }) .ContinueWith<bool>(s => { return true; }) .ContinueWith<string>(r => { if (r.Result) { return "Finished"; } else { return "Error"; } }); Console.WriteLine(SendFeedBackTask.Result);
首先输出Get some data,然后执行第二个获得返回值true,最后根据判断返回Finished或error。输出结果:
Get some Data!
Finished
其实上面的写法简化一下,可以这样写:
Task.Factory.StartNew<string>(() => {return "One";}).ContinueWith(ss => { Console.WriteLine(ss.Result);});
输出One,这个可以看明白了吧~
更多ContinueWith用法参见:http://technet.microsoft.com/zh-CN/library/dd321405
5、Task的取消
前面说了那么多Task的用法,下面来说下Task的取消,比如我们启动了一个task,出现异常或者用户点击取消等等,我们可以取消这个任务。
如何取消一个Task呢,我们通过cancellation的tokens来取消一个Task。在很多Task的Body里面包含循环,我们可以在轮询的时候判断IsCancellationRequested属性是否为True,如果是True的话就return或者抛出异常,抛出异常后面再说,因为还没有说异常处理的东西。
下面在代码中看下如何实现任务的取消,代码如下:
var tokenSource = new CancellationTokenSource(); var token = tokenSource.Token; var task = Task.Factory.StartNew(() => { for (var i = 0; i < 1000; i++) { System.Threading.Thread.Sleep(1000); if (token.IsCancellationRequested) { Console.WriteLine("Abort mission success!"); return; } } }, token); token.Register(() => { Console.WriteLine("Canceled"); }); Console.WriteLine("Press enter to cancel task..."); Console.ReadKey(); tokenSource.Cancel();
Console.ReadKey();//这句忘了加,程序退出了,看不到“Abort mission success!“这个提示
这里开启了一个Task,并给token注册了一个方法,输出一条信息,然后执行ReadKey开始等待用户输入,用户点击回车后,执行tokenSource.Cancel方法,取消任务。其输出结果如下:
以上是关于C# - Task(任务)和Thread(线程)的区别的主要内容,如果未能解决你的问题,请参考以下文章
C#中的Task.Delay()和Thread.Sleep()区别
C#的 Task,Thread,ThreadPool 之间有啥异同