溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

C#并發(fā)編程之Task類怎么使用

發(fā)布時間:2023-03-27 09:40:04 來源:億速云 閱讀:113 作者:iii 欄目:開發(fā)技術(shù)

這篇文章主要介紹了C#并發(fā)編程之Task類怎么使用的相關(guān)知識,內(nèi)容詳細易懂,操作簡單快捷,具有一定借鑒價值,相信大家閱讀完這篇C#并發(fā)編程之Task類怎么使用文章都會有所收獲,下面我們一起來看看吧。

Task.Run

Task是建立在線程池之上的一種多線程技術(shù),它的出現(xiàn)使Thread成為歷史。其使用方法非常簡單,下面在頂級語句中做一個簡單的例子

void printN(string name)
{
    for (int i = 0; i < 3; i++)
    {
        Console.WriteLine($"{name}:{i}");
        Task.Delay(1000).Wait();
    }
}
Task.Run(() => printN("t1"));
Task.Run(() => printN("t2"));
Task.Run(() => printN("t3")).Wait();

運行后,命令行中的結(jié)果為

t3:0
t2:0
t1:0
t2:1
t3:1
t1:1
t1:2
t2:2
t3:2

Task.Run通過輸入一個委托,創(chuàng)建一個任務(wù)并執(zhí)行,同時返回一個Task對象。

Task在執(zhí)行過程中,并不會等待命令行的主線程,所以在最后啟動的Task后跟上Wait,即等待該線程結(jié)束之后,主線程才結(jié)束,從而讓printN的輸出內(nèi)容得以在終端中顯示。

Task類

上面的Task.Run的案例也可以用Task來實現(xiàn),但Task對象創(chuàng)建后,并不會馬上運行,而會在Start()之后運行,示例如下

void printN(object name)
{
    for (int i = 0; i < 3; i++)
    {
        Console.WriteLine($"{name}:{i}");
        Task.Delay(1000).Wait();
    }
}
Action<object> act = (object name) => printN(name);

Task t1 = new Task(()=>printN("t1"));
new Task(act, "t2").Start();
Task t3 = new Task(act, "t3");
t1.Start();
t3.Start();
t3.Wait();

返回值

除了Task,C#還提供了帶有返回值的封裝,即Task<TResult>,可通過泛型的方式聲明返回值。

但是,Task說到底還是個類,而非函數(shù),這個返回值并不會在構(gòu)造函數(shù)中體現(xiàn)出來,也不經(jīng)過Start()函數(shù),若想使用這個返回值,需要經(jīng)由ContinueWith函數(shù)。

ContinueWith的功能是在某一個線程執(zhí)行完畢之后,開啟下一個線程。如果執(zhí)行完畢的線程有返回值的話,那么ContinueWith也可以利用這個返回值。

其調(diào)用方法為

Task<int> task = new Task<int>(() =>
{
    Console.WriteLine("這里是task");
    return 100;
});

//任務(wù)完成時執(zhí)行處理。
Task cwt = task.ContinueWith(t =>
{
    Console.WriteLine($"這里是Continue,task返回值為{t.Result}");
});
task.Start();
cwt.Wait();

其中,cwt需要等待task執(zhí)行完畢之后再執(zhí)行。

等待和延續(xù)

在前面的案例中,已經(jīng)講解了基本的等待函數(shù)Wait和基本的延續(xù)函數(shù)ContinueWith。C#中提供了更多的等待與延續(xù)函數(shù),以更加靈活地操作線程列表。


阻塞主線程不阻塞主線程
任意線程執(zhí)行完畢即可執(zhí)行WaitAnyWhenAny
所有線程執(zhí)行完畢方可執(zhí)行WaitAllWhenAll

其中, WhenAny, WhenAll需要與ContinueWith配合食用,當(dāng)WhenXX結(jié)束之后,即執(zhí)行ContinueWith中的內(nèi)容,這個過程并不阻塞主線程。

為了驗證這些函數(shù)的功能,先創(chuàng)建一個線程列表

Action<string, int> log = (name, time) =>
{
    Console.WriteLine($"{name} Start...");
    Task.Delay(time).Wait();
    Console.WriteLine($"{name} Stop!");
};

Task[] tasks = new Task[]
{
    Task.Run(() => log("A",3000)),
    Task.Run(() => log("B",1000)),
    Task.Run(() => log("C",2000))
};

然后依次執(zhí)行這幾個等待函數(shù),看看結(jié)果

Task.WaitAny(tasks); 此時當(dāng)B執(zhí)行完畢之后,阻塞就結(jié)束了,從而主線程結(jié)束。

B Start...
A Start...
C Start...
B Stop!

Task.WaitAll(tasks); 這次當(dāng)所有線程執(zhí)行完畢之后,程序才結(jié)束。

A Start...
B Start...
C Start...
B Stop!
C Stop!
A Stop!

下面這兩組測試,現(xiàn)象和前兩組相似,區(qū)別無非是在后面加上一段字符串而已。

Task.WhenAny(tasks).ContinueWith(x => Console.WriteLine($"某個Task執(zhí)行完畢")).Wait();
Task.WhenAll(tasks.ToArray()).ContinueWith(x => Console.WriteLine("所有Task執(zhí)行完畢")).Wait();

取消任務(wù)

C#提供了CancellationToken作為Task取消的標(biāo)識,通過調(diào)用Cancel()函數(shù),可將其取消標(biāo)志更改為True,從而在線程執(zhí)行過程中,起到取消線程的作用。

首先創(chuàng)建一個可以取消的線程函數(shù)

int TaskMethod(string name, int seconds, CancellationToken token)
{
    Console.WriteLine($"{name} 正在運行");
    for (int i = 0; i < seconds; i++)
    {
        Task.Delay(1000).Wait();
        Console.WriteLine($"{name}: {i}s");
        if (token.IsCancellationRequested)
            return -1;
    }
    return 1;
}

功能很簡單,就是跑循環(huán),在跑循環(huán)的過程中,如果token指明取消,則線程結(jié)束。

下面測試一下

var cts = new CancellationTokenSource();
var task = new Task<int>(() => TaskMethod("Task 1", 5, cts.Token), cts.Token);
Console.WriteLine($"線程狀態(tài):{task.Status}");
task.Start();
Console.WriteLine($"線程狀態(tài):{task.Status}");
Task.Delay(3000).Wait();
cts.Cancel();
Console.WriteLine($"線程狀態(tài):{task.Status}");
Task.Delay(1000).Wait();
Console.WriteLine($"線程狀態(tài):{task.Status}");

效果為如下

線程狀態(tài):Created
線程狀態(tài):WaitingToRun
Task 1 正在運行
Task 1: 0s
Task 1: 1s
線程狀態(tài):Running
Task 1: 2s
線程狀態(tài):RanToCompletion

在整個線程執(zhí)行的過程中,共出現(xiàn)了四種狀態(tài)

  • Created 此時線程剛創(chuàng)建,但并未執(zhí)行

  • WaitingToRun 此時已經(jīng)執(zhí)行了Start函數(shù),但線程還沒反應(yīng)過來,所以是等待執(zhí)行

  • Running 此時已經(jīng)執(zhí)行了Cancel,但task中的循環(huán)每1秒檢測1次,在Cancel執(zhí)行完之后,還沒來得及檢測,就查詢了線程的狀態(tài),所以線程仍在運行

  • RanToCompletion 在等待1秒之后,終于檢測到token變了,從而線程結(jié)束。

關(guān)于“C#并發(fā)編程之Task類怎么使用”這篇文章的內(nèi)容就介紹到這里,感謝各位的閱讀!相信大家對“C#并發(fā)編程之Task類怎么使用”知識都有一定的了解,大家如果還想學(xué)習(xí)更多知識,歡迎關(guān)注億速云行業(yè)資訊頻道。

向AI問一下細節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI