[.NET]Thread与Task的区别
前言
在学习Thread和Task之前,首先要理解以下概念:
- 进程与线程
- 同步与异步
- 阻塞与非阻塞
1、进程(process)
当一个程序开始运行时,它就是一个进程,进程包括运行中的程序和程序所使用到的内存和系统资源。
而一个进程又是由多个线程所组成的。
2、线程(thread)
线程是程序中的一个执行流,每个线程都有自己的专有寄存器(栈指针、程序计数器等),但代码区是共享的。
多线程是指程序中包含多个执行流,即在一个程序中可以同时运行多个不同的线程来执行不同的任务,也就是说允许单个程序创建多个并行执行的线程来完成各自的任务。
3、同步(sync)
发出一个功能调用时,在没有得到结果之前,该调用就不返回。
4、异步(async)
与同步相对,调用在发出之后,这个调用就直接返回了,所以没有返回结果。当这个调用完成后,一般通过状态、通知和回调来通知调用者。对于异步调用,调用的返回并不受调用者控制。
通知调用者的三种方式:
- 状态:即监听被调用者的状态(轮询),调用者需要每隔一定时间检查一次,效率会很低。
- 通知:当被调用者执行完成后,发出通知告知调用者,无需消耗太多性能。
- 回调:与通知类似,当被调用者执行完成后,会调用调用者提供的回调函数。
5、阻塞(block)
阻塞调用是指调用结果返回(或者收到通知)之前,当前线程会被挂起,即不继续执行后续操作。
简单来说,等前一件做完了才能做下一件事。
6、非阻塞(non-block)
非阻塞调用指在不能立刻得到结果之前,该调用不会阻塞当前线程。
什么是 Thread
.NET Framework 在 System.Threading
下提供线程的相关类。一个线程是一组执行指令。
什么是 Task
.NET Framework 提供了 Threading.Task
类,允许创建任务和异步运行它们。Task
有Wait、ContinueWith、Cancel等操作,有返回值。
Thread与Task的区别
Thread
类主要用于实现线程的创建以及执行。
Task
类表示以异步方式执行的单个操作。
1、Task
是基于 Thread
的,是比较高层级的封装,Task
最终还是需要 Thread
来执行
2、Task
默认使用后台线程执行,Thread
默认使用前台线程
static void Main(string[] args)
{
Thread thread = new Thread(obj => { Thread.Sleep(3000); });
thread.Start();
}
上面代码,主程序在3秒后结束。
static void Main(string[] args)
{
Task<int> task = new Task<int>(() =>
{
Thread,Sleep(3000);
return 1;
});
task.Start();
}
而这段代码,会瞬间结束。
3、Task
可以有返回值,Thread
没有返回值
虽然 Thread
可以通过 Start 方法参数来进行返回值处理,但十分不便。
public void Start (object parameter);
static void Main(string[] args)
{
Task task = new Task(LongRunningTask);
task.Start();
Console.WriteLine(task.Result);
}
private static int LongRunningTask()
{
Thread.Sleep(3000);
return 1;
}
4、Task
可以执行后续操作,Thread
不能执行后续操作
static void Main(string[] args)
{
Task task = new Task(LongRunningTask);
task.Start();
Task childTask = task.ContinueWith(SquareOfNumber);
Console.WriteLine("Sqaure of number is :"+ childTask.Result);
Console.WriteLine("The number is :" + task.Result);
}
private static int LongRunningTask()
{
Thread.Sleep(3000);
return 2;
}
private static int SquareOfNumber(Task obj)
{
return obj.Result * obj.Result;
}
5、Task
可取消任务执行,Thread
不行
static void Main(string[] args)
{
using (var cts = new CancellationTokenSource())
{
Task task = new Task(() => { LongRunningTask(cts.Token); });
task.Start();
Console.WriteLine("Operation Performing...");
if(Console.ReadKey().Key == ConsoleKey.C)
{
Console.WriteLine("Cancelling..");
cts.Cancel();
}
Console.Read();
}
}
private static void LongRunningTask(CancellationToken token)
{
for (int i = 0; i < 10000000; i++)
{
if(token.IsCancellationRequested)
{
break;
}
else
{
Console.WriteLine(i);
}
}
}
6、异常传播
Thread
在父方法上获取不到异常,而 Task
可以。