前言
在學習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
可以。