Task.Run
是在 dotnet framework 4.5 之后才可以使用, Task.Factory.StartNew
可以使用比 Task.Run
更多的參數,可以做到更多的定制。
可以認為 Task.Run
是簡化的 Task.Factory.StartNew
的使用,除了需要指定一個線程是長時間占用的,否則就使用 Task.Run
創建新線程
下面來告訴大家使用兩個函數創建新的線程
Task.Run(() => { var foo = 2; });
這時 foo 的創建就在另一個線程,需要知道 Task.Run 用的是線程池,也就是不是調用這個函數就會一定創建一個新的線程,但是會在另一個線程運行。
Task.Factory.StartNew(() => { ar foo = 2; });
可以看到,兩個方法實際上是沒有差別,但是Task.Run
比較好看,所以推薦使用Task.Run
。
等待線程
創建的線程,如果需要等待線程執行完成在繼續,那么可以使用 await 等待
private static async void SeenereKousa() { Console.WriteLine("開始 線程"+Thread.CurrentThread.ManagedThreadId); await Task.Run(() => { Console.WriteLine("進入 線程" + Thread.CurrentThread.ManagedThreadId); }); Console.WriteLine("退出 線程"+Thread.CurrentThread.ManagedThreadId); }
但是需要說的是這里使用 await 主要是給函數調用的外面使用,上面代碼在函數里面使用 await 函數是 void 那么和把代碼放在 task 里面是相同
private static async void SeenereKousa() { Console.WriteLine("開始 線程"+Thread.CurrentThread.ManagedThreadId); await Task.Run(() => { Console.WriteLine("進入 線程" + Thread.CurrentThread.ManagedThreadId); Console.WriteLine("退出 線程"+Thread.CurrentThread.ManagedThreadId); }); }
但是如果把 void 修改為 Task ,那么等待線程才有用
除了使用 await 等待,還可以使用 WaitAll 等待
Console.WriteLine("開始 線程" + Thread.CurrentThread.ManagedThreadId); var t = Task.Run(() => { Console.WriteLine("進入 線程" + Thread.CurrentThread.ManagedThreadId); }); Task.WaitAll(t); Console.WriteLine("退出 線程" + Thread.CurrentThread.ManagedThreadId);
使用 WaitAll 是在調用 WaitAll 的線程等待,也就是先在線程 1 運行,然后異步到 線程2 運行,這時線程1 等待線程2運行完成再繼續,所以輸出
開始 線程1 進入 線程2 退出 線程1
長時間運行
兩個函數最大的不同在於 Task.Factory.StartNew
可以設置線程是長時間運行,這時線程池就不會等待這個線程回收
Task.Factory.StartNew(() => { for (int i = 0; i < 100; i++) { var foo = 2; } Console.WriteLine("進行 線程" + Thread.CurrentThread.ManagedThreadId); }, TaskCreationOptions.LongRunning);
所以在需要設置線程是長時間運行的才需要使用 Task.Factory.StartNew
不然就使用 Task.Run
調用 Task.Run(foo)
就和使用下面代碼一樣
Task.Factory.StartNew(foo, CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default);