欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

c# 面試必備線程基礎(chǔ)知識(shí)點(diǎn)

 更新時(shí)間:2020年11月10日 11:10:17   作者:精致碼農(nóng) • 王亮  
這篇文章主要介紹了c# 面試必備線程基礎(chǔ)知識(shí)點(diǎn),幫助大家更好的鞏固,掌握線程的基礎(chǔ)知識(shí),感興趣的朋友可以了解下

線程的知識(shí)太多,知識(shí)點(diǎn)有深有淺,往深的研究會(huì)涉及操作系統(tǒng)、CPU、內(nèi)存,往淺了說(shuō)就是一些語(yǔ)法。沒(méi)有一定的知識(shí)積累,很難把線程的知識(shí)寫(xiě)得全面,當(dāng)然我也沒(méi)有這個(gè)能力。所以想到一個(gè)點(diǎn)寫(xiě)一個(gè)點(diǎn),盡量總結(jié)一些有用的知識(shí)點(diǎn)。線程是個(gè)大話(huà)題,這個(gè)系列可能會(huì)有好幾遍關(guān)于線程的,先從基礎(chǔ)的開(kāi)始,熱熱身。

一些基礎(chǔ)概念

線程(Thread)是操作系統(tǒng)能夠進(jìn)行運(yùn)算調(diào)度的最小單位。它是進(jìn)程中的實(shí)際運(yùn)作單位,一個(gè)進(jìn)程中可以啟動(dòng)多個(gè)線程,每個(gè)線程可以并行執(zhí)行不同的任務(wù)。嚴(yán)格意義上來(lái)說(shuō),同一時(shí)間可以并行運(yùn)行的線程數(shù)取決于 CPU 的核數(shù)。

根據(jù)線程運(yùn)行模式,可以把線程分為前臺(tái)線程、后臺(tái)線程和守護(hù)(Daemon)線程:

  • 前臺(tái)線程:主程序必須等待線程執(zhí)行完畢后才可退出程序。C# 中的 Thread 默認(rèn)為前臺(tái)線程,也可以設(shè)置為后臺(tái)線程。
  • 后臺(tái)線程:主程序執(zhí)行完畢立即跟隨退出,不管線程是否執(zhí)行完畢。C# 的 ThreadPool 管理的線程默認(rèn)為后臺(tái)線程。
  • 守護(hù)線程:守護(hù)線程擁有自動(dòng)結(jié)束自己生命周期的特點(diǎn),它通常被用來(lái)執(zhí)行一些后臺(tái)任務(wù)。

每次開(kāi)啟一個(gè)新的線程都要消耗一定的內(nèi)存,即使線程什么也不做,也會(huì)至少消耗 1M 左右的內(nèi)存。

多線程并行(Parallelism)和并發(fā)(Concurrency)的區(qū)別:

  • 并行:同一時(shí)刻有多條指令在多個(gè)處理器上同時(shí)執(zhí)行,無(wú)論從宏觀還是微觀上都是同時(shí)發(fā)生的。
  • 并發(fā):是指在同一時(shí)間段內(nèi),宏觀上看多個(gè)指令看起來(lái)是同時(shí)執(zhí)行,微觀上看是多個(gè)指令進(jìn)程在快速的切換執(zhí)行,同一時(shí)刻可能只有一條指令被執(zhí)行。

PS:以上概念來(lái)源 Google 的多個(gè)搜索結(jié)果,稍加整理。

Thread、ThreadPool 和 Task

對(duì) C# 開(kāi)發(fā)者來(lái)說(shuō),不可不理解清楚 Thread、ThreadPool 和 Task 這三個(gè)概念。這也是面試頻率很高的話(huà)題,在 StackOverflow 可以找到有很多不錯(cuò)的回答,我總結(jié)整理了一下。

Thread

Thread 是一個(gè)實(shí)際的操作系統(tǒng)級(jí)別的線程(OS 線程),有自己的棧和內(nèi)核資源。Thread 允許最高程度的控制,你可以 Abort、Suspend 或 Resume 一個(gè)線程,你還可以監(jiān)聽(tīng)它的狀態(tài),設(shè)置它的堆棧大小和 Culture 等屬性。Thread 的開(kāi)銷(xiāo)成本很高,你的每一個(gè)線程都會(huì)為它的堆棧消耗相對(duì)較多的內(nèi)存,并且在線程之間的處理器上下文切換時(shí)會(huì)增加額外的 CPU 開(kāi)銷(xiāo)。

ThreadPool

ThreadPool(線程池)是一堆線程的包裝器,由 CLR 維護(hù)。你對(duì)線程池中的線程沒(méi)有任何控制權(quán),你甚至無(wú)法知道線程池什么時(shí)候開(kāi)始執(zhí)行你提交的任務(wù),你只能控制線程池的大小。簡(jiǎn)單來(lái)說(shuō),線程池調(diào)用線程的機(jī)制是,它首先調(diào)用已創(chuàng)建的空閑線程來(lái)執(zhí)行你的任務(wù),如果當(dāng)前沒(méi)有空閑線程,可能會(huì)創(chuàng)建新線程,也可能會(huì)等待。

使用 ThreadPool 可以避免創(chuàng)建太多線程的開(kāi)銷(xiāo)。但是,如果你向 ThreadPool 提交了太多長(zhǎng)時(shí)間運(yùn)行的任務(wù),它可能會(huì)被填滿(mǎn),這時(shí)你提交的后面的任務(wù)可能最終會(huì)等待前面的長(zhǎng)時(shí)間運(yùn)行的任務(wù)執(zhí)行完成。此外,線程池沒(méi)有提供任何方法來(lái)檢測(cè)一個(gè)工作任務(wù)何時(shí)完成(不像 Thread.Join()),也沒(méi)有方法來(lái)獲取結(jié)果。因此,ThreadPool 最好用于調(diào)用者不需要結(jié)果的短時(shí)操作。

Task

Task 是 TPL(Task Parallel Library)提供一個(gè)類(lèi),它在 Thread 和 TheadPool 之間提供了兩全其美的解決方案。和 ThreadPool 一樣,Task 并不創(chuàng)建自己的OS 線程。相反,Task 是由 TaskScheduler 調(diào)度器執(zhí)行的,默認(rèn)的調(diào)度器只是在 ThreadPool 上運(yùn)行。

與 ThreadPool 不同的是,Task 還允許你知道它完成的時(shí)間,并獲取返回一個(gè)結(jié)果。你可以在現(xiàn)有的 Task 上調(diào)用 ContinueWith(),使它在任務(wù)完成后運(yùn)行更多的代碼(如果它已經(jīng)完成,就會(huì)立即運(yùn)行回調(diào))。

你也可以通過(guò)調(diào)用 Wait() 來(lái)同步等待一個(gè)任務(wù)的完成(或者,通過(guò)獲取它的 Result 屬性)。與 Thread.Join() 一樣,這將阻塞調(diào)用線程,直到任務(wù)完成。通常不建議同步等待任務(wù)執(zhí)行完成,它使調(diào)用線程無(wú)法進(jìn)行任何其他工作。如果當(dāng)前線程要等待其它線程任務(wù)執(zhí)行完成,建議使用 async/await 異步等待,這樣當(dāng)前線程可以空閑出來(lái)去處理其它任務(wù),比如在 await Task.Delay() 時(shí),并不占用線程資源。

由于任務(wù)仍然在 ThreadPool 上運(yùn)行,因此不應(yīng)該將其用于長(zhǎng)時(shí)任務(wù)的執(zhí)行,因?yàn)樗鼈儠?huì)填滿(mǎn)線程池并阻塞新的工作任務(wù)。相反,Task 提供了一個(gè) LongRunning 選項(xiàng),它將告訴 TaskScheduler 啟用一個(gè)新的線程,而不是在 ThreadPool 上運(yùn)行。

所有較新的上層多線程 API,包括 Parallel.ForEach()、PLINQ、async/await 等,都是建立在 Task 上的。

Thread 和 Task 簡(jiǎn)單示例

下面通過(guò)一個(gè)簡(jiǎn)單示例演示 Thread 和 Task 的使用,注意他們是如何創(chuàng)建、傳參、執(zhí)行和等待執(zhí)行完成的。

static void Main(string[] args)
{
  // 創(chuàng)建兩個(gè)新的 Thread
  var thread1 = new Thread(new ThreadStart(() => PerformAction("Thread", 1)));
  var thread2 = new Thread(new ThreadStart(() => PerformAction("Thread", 2)));

  // 開(kāi)始執(zhí)行線程任務(wù)
  thread1.Start();
  thread2.Start();

  // 等待兩個(gè)線程執(zhí)行完成
  thread1.Join();
  thread1.Join();

  Console.WriteLine("Theads done!");

  Console.WriteLine("===我是分隔線===");

  // 創(chuàng)建兩個(gè)新的 Task
  var task1 = Task.Run(() => PerformAction("Task", 1));
  var task2 = Task.Run(() => PerformAction("Task", 2));

  // 執(zhí)行并等待兩個(gè) Task 執(zhí)行完成
  Task.WaitAll(new[] { task1, task2 });

  Console.WriteLine("Tasks done!");

  Console.ReadKey();
}

static void PerformAction(string threadOrTask, int id)
{
  var rnd = new Random(id);
  for (int i = 0; i < 5; i++)
  {
    Console.WriteLine($"{threadOrTask}: {id}: {i}", id, i);
    Thread.Sleep(rnd.Next(0, 1000));
  }
}

運(yùn)行效果:

注意到,相比之下 Task 比 Thread 好用得多,加上前文 Task 和 Thread 的對(duì)比,對(duì)我們編碼的指導(dǎo)意義是:大多數(shù)情況我們應(yīng)該使用 Task,而不要直接使用 Thread,除非你明確知道你需要一個(gè)獨(dú)立的線程來(lái)執(zhí)行一個(gè)長(zhǎng)耗時(shí)的任務(wù)。

小結(jié)

本篇內(nèi)容很基礎(chǔ),整理了 C# 線程編程有關(guān)的重要概念,簡(jiǎn)單演示了 Thread 和 Task 的使用。Thread 和 Task 是高頻面試話(huà)題,尤其是 Thread 和 Task 的區(qū)別,Thread 更底層,Task 更抽象,回答好這類(lèi)面試題的關(guān)鍵點(diǎn)在 ThreadPool。

作者:精致碼農(nóng)

出處:http://cnblogs.com/willick

以上就是c# 面試必備線程基礎(chǔ)知識(shí)點(diǎn)的詳細(xì)內(nèi)容,更多關(guān)于c# 線程基礎(chǔ)的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

最新評(píng)論