国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學(xué)院 > 開發(fā)設(shè)計(jì) > 正文

[多線程]thread,threadpool,task及TPL知識點(diǎn)整理

2019-11-17 02:43:07
字體:
供稿:網(wǎng)友

[多線程]thread,threadpool,task及TPL知識點(diǎn)整理

Posted on 2014-12-10 17:16 lsr_flying 閱讀(...) 評論(...) 編輯 收藏

簡單理解

Thread:是一個指令序列,個體對象。

Threadpool:在使用Thread的過程中,程序員要為每個希望并發(fā)的序列new一個線程,很麻煩,因此希望有一個統(tǒng)一管理線程的方法,程序員就不需要關(guān)注線程的申請管理問題,所以就對Thread進(jìn)行一系列封裝,有了ThreadPool。使用Threadpool,把需要并發(fā)的序列添加進(jìn)線程池,線程池根據(jù)其線程列表中的線程的空閑情況,動態(tài)為并發(fā)序列申請線程。

Task:再后來,程序員發(fā)現(xiàn)在使用Threadpool的過程當(dāng)中還是存在很多不便,比如:(1)ThreadPool不支持線程的取消、完成、失敗通知等交互性操作;(2)ThreadPool不支持線程執(zhí)行的先后次序;那么怎么辦,那就繼續(xù)對ThreadPool進(jìn)行封裝唄,于是.net Framework4.0有了TPL和Task。

Thread

  選用Thread的一個重要原因之一是因?yàn)樗腡hread.Sleep()成員,因?yàn)樗赥ask或ThreadPool中都沒有等價(jià)物。不過如果不會帶來太多沒必要的復(fù)雜性,可以考慮用一個計(jì)時器代替Sleep()。

  對于Thread這個知識點(diǎn),重點(diǎn)在于同步、死鎖和競態(tài)等問題,感覺關(guān)鍵點(diǎn)在于對lock()和WaitHandler的理解。這里,介紹下參數(shù)的傳遞和獲取。

  下面這部分主要查看MSDN的文檔:http://msdn.microsoft.com/en-us/library/wkays279.aspx

  • 向線程傳遞參數(shù)

  因?yàn)門hread的構(gòu)造函數(shù)需要傳遞一個無返回類型和無參的委托引用,因此最理想的辦法是把需要傳遞給線程的方法封裝在一個類里面,然后將需要傳遞給這個線程的參數(shù)定義為該類的字段。比如,要把下面這個帶參函數(shù)通過線程調(diào)用:

1 public double CalArea(double length,double width)2 {3 double Area=length*width;4 return Area;5 }

  

  可使用如下方法進(jìn)行:

 1 public class AreaClass 2 { 3 public double width; 4 public double length; 5 public double area; 6 public void CalArea() 7 { 8 area=width*length; 9 }10 }11 12 public void TestAreaCal()13 {14 AreaClass areaCal=new AreaClass();15 System.Threading.Thread thread1=new System.Threading.Thread(areaCal.CalArea);16 areaCal.width=2;17 areaCal.length=3;18 thread1.start();19 }

  但要注意,如果在執(zhí)行完thread1.start()之后,立刻查看areaCal.area的值,并不一定就存在了。要獲得有效的返回值得簡單方法將在下面介紹。

 

  • 獲取線程返回值

  簡單方法是使用BackgroundWorker類。利用BackgroundWorker類管理你的線程,并在線程執(zhí)行完畢后產(chǎn)生一個事件,然后在對應(yīng)的事件處理函數(shù)中處理結(jié)果。

 1 class AreaClass2 2 { 3     public double Base; 4     public double Height; 5     public double CalcArea() 6     { 7         // Calculate the area of a triangle.  8         return 0.5 * Base * Height; 9     }10 }11 12 PRivate System.ComponentModel.BackgroundWorker BackgroundWorker113     = new System.ComponentModel.BackgroundWorker();14 15 private void TestArea2()16 {17     InitializeBackgroundWorker();18 19     AreaClass2 AreaObject2 = new AreaClass2();20     AreaObject2.Base = 30;21     AreaObject2.Height = 40;22 23     // Start the asynchronous Operation.24     BackgroundWorker1.RunWorkerAsync(AreaObject2);25 }26 27 private void InitializeBackgroundWorker()28 {29     // Attach event handlers to the BackgroundWorker object.30     BackgroundWorker1.DoWork +=31         new System.ComponentModel.DoWorkEventHandler(BackgroundWorker1_DoWork);32     BackgroundWorker1.RunWorkerCompleted +=33         new System.ComponentModel.RunWorkerCompletedEventHandler(BackgroundWorker1_RunWorkerCompleted);34 }35 36 private void BackgroundWorker1_DoWork(37     object sender,38     System.ComponentModel.DoWorkEventArgs e)39 {40     AreaClass2 AreaObject2 = (AreaClass2)e.Argument;41     // Return the value through the Result property.42     e.Result = AreaObject2.CalcArea();43 }44 45 private void BackgroundWorker1_RunWorkerCompleted(46     object sender,47     System.ComponentModel.RunWorkerCompletedEventArgs e)48 {49     // access the result through the Result property. 50     double Area = (double)e.Result;51     MessageBox.Show("The area is: " + Area.ToString());52 }

ThreadPool

ThreadPool是一個靜態(tài)類。

管理過程:

許多程序生成的線程有一大半時間處在休眠狀態(tài),直到產(chǎn)生一個事件喚醒它們,另一部分線程只會被周期性地喚醒以更改狀態(tài)信息。ThreadPool可以通過為你的應(yīng)用程序提供由系統(tǒng)管理的線程來提高應(yīng)用程序?qū)€程的使用率。線程池中會有一個線程監(jiān)看線程池隊(duì)列中的等待操作,當(dāng)線程池中的線程完成它的任務(wù)后,它就會回到等待線程的隊(duì)列當(dāng)中,等待重新使用。如果線程池中的所有線程都在運(yùn)行,那么新的任務(wù)會加進(jìn)等待隊(duì)列中。對線程的重復(fù)使用降低了為每一個任務(wù)都開啟一個新線程的造成的程序開銷。

特點(diǎn):

ThreadPool里面的線程管理是由類庫(或操作系統(tǒng))完成的,而不是由應(yīng)用程序進(jìn)行管理。

線程池里面的線程都是后臺線程(即它們的isBackgroud屬性為true)。也就意味著當(dāng)所有前臺線程都運(yùn)行完畢后,線程池的線程不會保持程序的運(yùn)行。

線程池一般使用在服務(wù)應(yīng)用程序上。每個進(jìn)來的請求都分配給線程池中的每一個線程,這樣就可以異步處理各個請求。

使用:

線程池的簡單使用可通過QueueUserWorkItem方法進(jìn)行。如果需要向任務(wù)中傳遞參數(shù),可以通過傳遞一個state object來進(jìn)行,如果有多個參數(shù)要傳遞,可將多個參數(shù)封裝在結(jié)構(gòu)或?qū)ο蟮淖侄萎?dāng)中。但要注意,一旦一個方法加入了線程隊(duì)列,就無法取消該方法的執(zhí)行

public static void Main(){System.Threading.ThreadPool.QueueUserWorkItem(new System.Threading.WaitCallback(ASynTask),ASynData);//other code snippets......}public void ASynTask(object state){//codes need to executed asynchronously}

線程池的大小可以通過GetMaxThreads或SetMaxThreads方法訪問或設(shè)置,但注意過大或過小都會影響程序的性能。

另外,獲取ThreadPool返回值有兩種方法,具體查看上面Thread所講的辦法。

Task和TPL

  關(guān)于Task和TPL的知識還是以后再詳細(xì)介紹。這里簡單講下Task的主要特征。

  •   Task包含一個ContinueWith()方法,它的作用是將任務(wù)鏈接起來,只要鏈中的第一個任務(wù)完成,就會觸發(fā)已登記在它之后執(zhí)行的其它任務(wù)。還有個有趣的地方,可以用ContinueWith()添加多個任務(wù),在先驅(qū)任務(wù)(父任務(wù))完成后,添加的所有任務(wù)都會開始并行運(yùn)行。另外,可以在ContinueWith()語句有一個TaskContinuationOpitons枚舉值,通過指定該值,可根據(jù)先驅(qū)任務(wù)的運(yùn)行情況決定是否運(yùn)行子任務(wù)。
  •   支持協(xié)作式取消任務(wù)。通過使用System.Threading.CancellationToken來進(jìn)行。一個線程通過設(shè)置CancellationToken(struct類型)請求取消任務(wù),運(yùn)行的線程通過檢查該CancellationToken決定是否繼續(xù)運(yùn)行。還有個值得關(guān)注的地方就是,通過CancellationToken終止的線程,如果不會在某些方面造成破壞,不會使線程的Faulted屬性為true。
 1 public static void Main() 2 { 3     CancellationTokenSource cancellationTokenSource=new CancellationTokenSource(); 4     Task task.Task.Factory.StartNew(()=>LoopWork(cancellationTokenSource.Token),cancellationTokenSource.Token); 5     Thread.sleep(1000); 6     cancellationTokenSource.Cancel(); 7    task.wait(); 8 } 9 10 private static void LoopWork(CancellationToken cancellationToken)11 {12    while(!cancellationToken.IsCancellationRequested)13   {14      //work need to be done15   }16 }

Task還支持IDisposable方法,這是支持Wait()功能所需要的。

并行迭代

在使用for循環(huán)迭代時,處理器會按順序依次迭代。但如果每次迭代之間互不影響,而且如果系統(tǒng)有多個處理器,我們可以讓每個處理器都負(fù)責(zé)一個迭代,從而提高效率。

相關(guān)類:System.Threading.Tasks.Parallel。

相關(guān)方法:Parallel.For()和Parallel.Foreach()

注意三點(diǎn):計(jì)算機(jī)具有多個處理器,并行迭代的順序不是固定的,在使用時還要同時考慮迭代內(nèi)部代碼的非原子性帶來的競態(tài)問題。

 1 //將10000個小寫單詞變成大寫 2 static void Main() 3 { 4    int iterations=10000; 5    string[] Word=new string[iterations]; 6    //此處初始化word,輸入10000個小寫單詞 7   Parallel.For(0,iterations,(i)=> 8     { 9        word[i]=word[i].toUpper();10     });11 }    


發(fā)表評論 共有條評論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 丰镇市| 宁陵县| 阳信县| 庆云县| 安新县| 普陀区| 米泉市| 怀来县| 巴青县| 呼图壁县| 如皋市| 浙江省| 永和县| 太谷县| 赫章县| 福建省| 宁城县| 潼关县| 枣阳市| 武功县| 金山区| 溆浦县| 富川| 安达市| 辽阳市| 舞阳县| 崇州市| 秭归县| 邵武市| 保定市| 华蓥市| 韶关市| 乌兰察布市| 电白县| 张家口市| 大同县| 北安市| 海城市| 集安市| 博湖县| 涪陵区|