C#中Task任務(wù)類用法詳解
前言
Task類是.NET平臺(tái)上進(jìn)行多線程和異步操作的重要工具。它提供了簡潔而強(qiáng)大的API支持,使得開發(fā)者能夠更加高效地利用系統(tǒng)資源,實(shí)現(xiàn)復(fù)雜的并行和異步操作。無論是在I/O密集型操作還是CPU密集型任務(wù)中,Task類都能為開發(fā)者提供有力的支持。
認(rèn)識(shí)Task
命名空間:System.Threading.Tasks
類名:Task
Task顧名思義就是任務(wù)的意思
Task是在線程池基礎(chǔ)上進(jìn)行的改進(jìn),它擁有線程池的優(yōu)點(diǎn),同時(shí)解決了使用線程池不易控制的弊端。
它是基于線程池的優(yōu)點(diǎn)對(duì)線程的封裝,可以讓我們更方便高效的進(jìn)行多線程開發(fā)。
簡單理解:
Task的本質(zhì)是對(duì)線程Thread的封裝,它的創(chuàng)建遵循線程池的優(yōu)點(diǎn),并且可以更方便的讓我們控制線程。
一個(gè)Task對(duì)象就是一個(gè)線程。
創(chuàng)建無返回值Task的三種方式
第一種方式
通過new一個(gè)Task對(duì)象傳入委托函數(shù)并啟動(dòng)
Task t1 = new Task(() => { int i = 0; while (isRuning) { print("方式一:" + i); ++i; Thread.Sleep(1000); } }); t1.Start();
第二種方式
通過Task中的Run靜態(tài)方法傳入委托函數(shù)
Task t2 = Task.Run(() => { int i = 0; while (isRuning) { print("方式二:" + i); ++i; Thread.Sleep(1000); } });
第三種方式
通過Task.Factory中的StartNew靜態(tài)方法傳入委托函數(shù)
Task t3 = Task.Factory.StartNew(() => { int i = 0; while (isRuning) { print("方式三:" + i); ++i; Thread.Sleep(1000); } });
返回有返回值的Task
第一種方式
通過new一個(gè)Task對(duì)象闖入委托函數(shù)并啟動(dòng)
t1 = new Task<int>(() => { int i = 0; while (isRuning) { print("方式一:" + i); ++i; Thread.Sleep(1000); } return 1; }); t1.Start();
第二種方式
通過Task中的Run靜態(tài)方法傳入委托函數(shù)
t2 = Task.Run<string>(() => { int i = 0; while (isRuning) { print("方式二:" + i); ++i; Thread.Sleep(1000); } return "1231"; });
第三種方式
通過Task.Factory中的StartNew靜態(tài)方法傳入委托函數(shù)
t3 = Task.Factory.StartNew<float>(() => { int i = 0; while (isRuning) { print("方式三:" + i); ++i; Thread.Sleep(1000); } return 4.5f; });
獲取返回值
注意:
Resut獲取結(jié)果時(shí)會(huì)阻塞線程
即如果task沒有執(zhí)行完成
會(huì)等待task執(zhí)行完成獲取到Result
然后再執(zhí)行后邊的代碼,也就是說 執(zhí)行到這句代碼時(shí) 由于我們的Task中是死循環(huán)
所以主線程就會(huì)被卡死
同步執(zhí)行Task
之前我們舉的例子都是通過多線程異步執(zhí)行的
如果希望Task能夠同步執(zhí)行
只需要調(diào)用Task對(duì)象中的RunSynchronously方法
注意:需要使用 new Task對(duì)象的方式,因?yàn)镽un和StartNew在創(chuàng)建時(shí)就會(huì)啟動(dòng)
Task t = new Task(() => { Thread.Sleep(1000); print("這是一段話"); }); //t.Start(); t.RunSynchronously(); print("主線程執(zhí)行");
不Start 而是 RunSynchronously
Task中線程阻塞的方式
1.Wait方法:等待任務(wù)執(zhí)行完畢,再執(zhí)行后面的內(nèi)容
Task t1 = Task.Run(() => { for (int i = 0; i < 5; i++) { print("t1:" + i); } }); Task t2 = Task.Run(() => { for (int i = 0; i < 20; i++) { print("t2:" + i); } }); ???????//t2.Wait();
2.WaitAny靜態(tài)方法:傳入任務(wù)中任意一個(gè)任務(wù)結(jié)束就繼續(xù)執(zhí)行
Task.WaitAny(t1, t2);
3.WaitAll靜態(tài)方法:任務(wù)列表中所有任務(wù)執(zhí)行結(jié)束就繼續(xù)執(zhí)行
Task.WaitAll(t1, t2);
Task完成后繼續(xù)其它Task(任務(wù)延續(xù))
1.WhenAll靜態(tài)方法 + ContinueWith方法:傳入任務(wù)完畢后再執(zhí)行某任務(wù)
using System.Threading; using System.Threading.Tasks; using UnityEngine; public class Test : MonoBehaviour { Task t1,t2; bool isRuning =true; void Start() { Task.WhenAll(t1, t2).ContinueWith((t) => { print("一個(gè)新的任務(wù)開始了"); int i = 0; while (isRuning) { print(i); ++i; Thread.Sleep(1000); } }); Task.Factory.ContinueWhenAll(new Task[] { t1, t2 }, (t) => { print("一個(gè)新的任務(wù)開始了"); int i = 0; while (isRuning) { print(i); ++i; Thread.Sleep(1000); } }); } private void OnDestroy() { isRuning = false; } }
2.WhenAny靜態(tài)方法 + ContinueWith方法:傳入任務(wù)只要有一個(gè)執(zhí)行完畢后再執(zhí)行某任務(wù)
using System.Threading; using System.Threading.Tasks; using UnityEngine; public class Test : MonoBehaviour { Task t1,t2; bool isRuning =true; void Start() { Task.WhenAny(t1, t2).ContinueWith((t) => { print("一個(gè)新的任務(wù)開始了"); int i = 0; while (isRuning) { print(i); ++i; Thread.Sleep(1000); } }); Task.Factory.ContinueWhenAny(new Task[] { t1, t2 }, (t) => { print("一個(gè)新的任務(wù)開始了"); int i = 0; while (isRuning) { print(i); ++i; Thread.Sleep(1000); } }); } private void OnDestroy() { isRuning = false; } }
取消Task執(zhí)行
方法一:通過加入bool標(biāo)識(shí) 控制線程內(nèi)死循環(huán)的結(jié)束
方法二:通過CancellationTokenSource取消標(biāo)識(shí)源類 來控制
CancellationTokenSource對(duì)象可以達(dá)到延遲取消、取消回調(diào)等功能
using System.Threading; using System.Threading.Tasks; using UnityEngine; public class Test : MonoBehaviour { Task t1,t2; CancellationTokenSource c; void Start() { c = new CancellationTokenSource(); //延遲取消 c.CancelAfter(5000); //取消回調(diào) c.Token.Register(() => { print("任務(wù)取消了"); }); Task.Run(() => { int i = 0; while (!c.IsCancellationRequested) { print("計(jì)時(shí):" + i); ++i; Thread.Sleep(1000); } }); } private void OnDestroy() { c.Cancel(); } }
總結(jié)
1.Task類是基于Thread的封裝
2.Task類可以有返回值,Thread沒有返回值
3.Task類可以執(zhí)行后續(xù)操作,Thread沒有這個(gè)功能
4.Task可以更加方便的取消任務(wù),Thread相對(duì)更加單一
5.Task具備ThreadPool線程池的優(yōu)點(diǎn),更節(jié)約性能
到此這篇關(guān)于C#中Task任務(wù)類用法詳解的文章就介紹到這了,更多相關(guān)C# Task任務(wù)類內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C#使用post發(fā)送和接收數(shù)據(jù)的方法
這篇文章主要介紹了C#使用post發(fā)送和接收數(shù)據(jù)的方法,涉及C#使用post收發(fā)數(shù)據(jù)的相關(guān)技巧,非常具有實(shí)用價(jià)值,需要的朋友可以參考下2015-04-04WPF實(shí)現(xiàn)XAML轉(zhuǎn)圖片的示例詳解
這篇文章主要為大家詳細(xì)介紹了如何利用WPF實(shí)現(xiàn)XAML轉(zhuǎn)圖片,文中的示例代碼講解詳細(xì),對(duì)我們學(xué)習(xí)或工作有一定幫助,感興趣的小伙伴可以了解一下2022-11-11C# 獲取打印機(jī)當(dāng)前狀態(tài)的方法
C# 獲取打印機(jī)當(dāng)前狀態(tài)的方法,需要的朋友可以參考一下2013-04-04C# TextBox控件實(shí)現(xiàn)只能輸入數(shù)字的方法
這篇文章主要介紹了C# TextBox控件實(shí)現(xiàn)只能輸入數(shù)字的方法,本文使用TextBox的keypress事件實(shí)現(xiàn)這個(gè)需求,需要的朋友可以參考下2015-06-06C#使用Clipboard類實(shí)現(xiàn)剪貼板功能
這篇文章介紹了C#使用Clipboard類實(shí)現(xiàn)剪貼板功能的方法,文中通過示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-06-06C#如何使用Bogus創(chuàng)建模擬數(shù)據(jù)示例代碼
這篇文章主要給大家介紹了關(guān)于C#如何使用Bogus創(chuàng)建模擬數(shù)據(jù)的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用C#具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧2019-04-04C#實(shí)現(xiàn)自由組合本地緩存、分布式緩存和數(shù)據(jù)查詢
這篇文章介紹了C#實(shí)現(xiàn)本地緩存、分布式緩存和數(shù)據(jù)查詢的方法,文中通過示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-07-07基于C#實(shí)現(xiàn)的端口掃描器實(shí)例代碼
這篇文章主要介紹了基于C#實(shí)現(xiàn)的端口掃描器實(shí)例代碼,需要的朋友可以參考下2014-07-07