1. 程式人生 > >使用Task代替ThreadPool和Thread(轉載)

使用Task代替ThreadPool和Thread(轉載)

原文地址:http://www.cnblogs.com/luminji/archive/2011/05/13/2044801.html

一:Task的優勢

ThreadPool相比Thread來說具備了很多優勢,但是ThreadPool卻又存在一些使用上的不方便。比如:

1: ThreadPool不支援執行緒的取消、完成、失敗通知等互動性操作;

2: ThreadPool不支援執行緒執行的先後次序;

以往,如果開發者要實現上述功能,需要完成很多額外的工作,現在,FCL中提供了一個功能更強大的概念:Task。Task線上程池的基礎上進行了優化,並提供了更多的API。在FCL4.0中,如果我們要編寫多執行緒程式,Task顯然已經優於傳統的方式。

以下是一個簡單的任務示例:

複製程式碼 staticvoid Main(string[] args)
{
Task t 
=new Task(() =>
{
Console.WriteLine(
"任務開始工作……");
//模擬工作過程Thread.Sleep(5000);
});
t.Start();
t.ContinueWith((task) 
=>
{
Console.WriteLine(
"任務完成,完成時候的狀態為:");
Console.WriteLine(
"IsCanceled={0}\tIsCompleted={1}\tIsFaulted={2}", task.IsCanceled, task.IsCompleted, task.IsFaulted);
});
Console.ReadKey();
}
複製程式碼


二:Task的完成狀態

任務Task有這樣一些屬性,讓我們查詢任務完成時的狀態:

1: IsCanceled,因為被取消而完成;

2: IsCompleted,成功完成;

3: IsFaulted,因為發生異常而完成

需要注意的是,任務並沒有提供回撥事件來通知完成(像BackgroundWorker一樣),它通過啟用一個新任務的方式來完成類似的功能。ContinueWith方法可以在一個任務完成的時候發起一個新任務,這種方式天然就支援了任務的完成通知:我們可以在新任務中獲取原任務的結果值。

       下面是一個稍微複雜一點的例子,同時支援完成通知、取消、獲取任務返回值等功能:

複製程式碼 staticvoid Main(string[] args)
{
CancellationTokenSource cts 
=new CancellationTokenSource();
Task
<int> t =new Task<int>(() => Add(cts.Token), cts.Token);
t.Start();
t.ContinueWith(TaskEnded);
//等待按下任意一個鍵取消任務Console.ReadKey();
cts.Cancel();
Console.ReadKey();
}

staticvoid TaskEnded(Task<int> task)
{
Console.WriteLine(
"任務完成,完成時候的狀態為:");
Console.WriteLine(
"IsCanceled={0}\tIsCompleted={1}\tIsFaulted={2}", task.IsCanceled, task.IsCompleted, task.IsFaulted);
Console.WriteLine(
"任務的返回值為:{0}", task.Result);
}

staticint Add(CancellationToken ct)
{
Console.WriteLine(
"任務開始……");
int result =0;
while (!ct.IsCancellationRequested)
{
result
++;
Thread.Sleep(
1000);
}
return result;
}
複製程式碼

在任務開始後大概3秒鐘的時候按下鍵盤,會得到如下的輸出:

任務開始……
任務完成,完成時候的狀態為:
IsCanceled
=False IsCompleted=True IsFaulted=False
任務的返回值為:
3

你也許會奇怪,我們的任務是通過Cancel的方式處理,為什麼完成的狀態IsCanceled那一欄還是False。這是因為在工作任務中,我們對於IsCancellationRequested進行了業務邏輯上的處理,並沒有通過ThrowIfCancellationRequested方法進行處理。如果採用後者的方式,如下:

複製程式碼 staticvoid Main(string[] args)
{
CancellationTokenSource cts 
=new CancellationTokenSource();
Task
<int> t =new Task<int>(() => AddCancleByThrow(cts.Token), cts.Token);
t.Start();
t.ContinueWith(TaskEndedByCatch);
//等待按下任意一個鍵取消任務Console.ReadKey();
cts.Cancel();
Console.ReadKey();
}

staticvoid TaskEndedByCatch(Task<int> task)
{
Console.WriteLine(
"任務完成,完成時候的狀態為:");
Console.WriteLine(
"IsCanceled={0}\tIsCompleted={1}\tIsFaulted={2}", task.IsCanceled, task.IsCompleted, task.IsFaulted);
try
{
Console.WriteLine(
"任務的返回值為:{0}", task.Result);
}
catch (AggregateException e)
{
e.Handle((err) 
=> err is OperationCanceledException);
}
}

staticint AddCancleByThrow(CancellationToken ct)
{
Console.WriteLine(
"任務開始……");
int result =0;
while (true)
{
ct.ThrowIfCancellationRequested();
result
++;
Thread.Sleep(
1000);
}
return result;
}
複製程式碼

那麼輸出為:

任務開始……
任務完成,完成時候的狀態為:
IsCanceled
=True IsCompleted=True IsFaulted=False

在任務結束求值的方法TaskEndedByCatch中,如果任務是通過ThrowIfCancellationRequested方法結束的,對任務求結果值將會丟擲異常OperationCanceledException,而不是得到丟擲異常前的結果值。這意味著任務是通過異常的方式被取消掉的,所以可以注意到上面程式碼的輸出中,狀態IsCancled為True。

再一次,我們注意到取消是通過異常的方式實現的,而表示任務中發生了異常的IsFaulted狀態卻還是等於False。這是因為ThrowIfCancellationRequested是協作式取消方式型別CancellationTokenSource的一個方法,CLR進行了特殊的處理。CLR知道這一行程式開發者有意為之的程式碼,所以不把它看作是一個異常(它被理解為取消)。要得到IsFaulted等於True的狀態,我們可以修改While迴圈,模擬一個異常出來:

複製程式碼 while (true)
{
//ct.ThrowIfCancellationRequested();if (result ==5)
{
thrownew Exception("error");
}
result
++;
Thread.Sleep(
1000);
}
複製程式碼

模擬異常後的輸出為:

任務開始……
任務完成,完成時候的狀態為:
IsCanceled
=False IsCompleted=True IsFaulted=True


三:任務工廠

Task還支援任務工廠的概念。任務工廠支援多個任務之間共享相同的狀態,如取消型別CancellationTokenSource就是可以被共享的。通過使用任務工廠,可以同時取消一組任務:

複製程式碼 staticvoid Main(string[] args)
{
CancellationTokenSource cts 
=new CancellationTokenSource();
//等待按下任意一個鍵取消任務TaskFactory taskFactory =new TaskFactory();
Task[] tasks 
=new Task[]
{
taskFactory.StartNew(() 
=> Add(cts.Token)),
taskFactory.StartNew(() 
=> Add(cts.Token)),
taskFactory.StartNew(() 
=> Add(cts.Token))
};
//CancellationToken.None指示TasksEnded不能被取消taskFactory.ContinueWhenAll(tasks, TasksEnded, CancellationToken.None);
Console.ReadKey();
cts.Cancel();
Console.ReadKey();
}

staticvoid TasksEnded(Task[] tasks)
{
Console.WriteLine(
"所有任務已完成!");
}
複製程式碼

以上程式碼輸出為:

任務開始……
任務開始……
任務開始……
所有任務已完成(取消)!

本建議演示了Task(任務)和TaskFactory(任務工廠)的使用方法。Task甚至進一步優化了後臺執行緒池的排程,加快了執行緒的處理速度。在FCL4.0時代,使用多執行緒,我們理應更多地使用Task。

相關推薦

使用Task代替ThreadPoolThread轉載

原文地址:http://www.cnblogs.com/luminji/archive/2011/05/13/2044801.html 一:Task的優勢 ThreadPool相比Thread來說具備了很多優勢,但是ThreadPool卻又存在一些使用上的不方便。比

Oracle學習筆記—Db_name、Db_domain、Global_name、Service_name、Instance_nameOracle_SID轉載

安全 文件中 分布 好處 避免 名稱 detail 數據庫安全 自動 轉載自: Oracle中DB_NAME,SID,DB_DOMAIN,SERVICE_NAME等之間的區別 Db_name:對一個數據庫(Oracle database)的唯一標識。這種表示對於單個數據

Dubbo學習配置轉載

ext.get 訂閱 這樣的 內存 com 消費者 list() 增加 引用 轉載自: 簡單了解下Dubbo 1. Dubbo是什麽? Dubbo是一個分布式服務框架,致力於提供高性能和透明化的RPC遠程服務調用方案,以及SOA服務治理方案。簡單的說,dubbo就是個服

Linux下MySQL的安裝啟動轉載

enable linu char cal mysql用戶 客戶端程序 ast 初學 unix 原文鏈接:http://www.linuxidc.com/Linux/2016-07/133234.htm 一、MySQL各類安裝方法的比較 在Linux系統下,MySQL有3種主

Ocata Neutron代碼分析——oslo_service中的ServiceLauncherProcessLauncher轉載

mic return cme down ice post you tin system 1.概述 Openstack中有一個叫Launcher的概念,即專門用來啟動服務的,這個類被放在了oslo_service這個包裏面。Launcher分為兩種,一種是ServiceL

計算機中的進制編碼轉載

理論 數量 8進制 技術 單位 中國 64bit cnblogs 屬於 原文出處: http://www.cnblogs.com/resn/p/5775378.html 古時候,人們是如何來傳遞消息的? 當年周幽王為博褒妃一笑,不顧眾臣反對,竟數次無故點燃邊關告急用的烽

SVN服務器的本地搭建使用轉載

copy jpg ise ngs pac 開發 沖突解決 其他人 作用 Subversion是優秀的版本控制工具,其具體的的優點和詳細介紹,這裏就不再多說. 首先來下載和搭建SVN服務器. 現在Subversion已經遷移到apache網站上了,下載地址: http://s

Java並發編程:TimerTimerTask轉載

為什麽 www isempty com 空間 continue 可執行 rate 一般來說 下面內容轉載自:   http://blog.csdn.net/xieyuooo/article/details/8607220   其實就Timer來講就是一個調度器,而Time

安卓sdk的下載安裝轉載

首先推薦一個國內的安卓應用 下載網站 http://www.androiddevtools.cn/ 推薦 安卓studio  下載安裝文章--僅供參考 https://blog.csdn.net/m0_37240709/article/details/7606917

jquery中$.ajax $.get $.post $.getJSON的區別用法轉載

首先,.get和.get和.post其實都是.ajax的一種,在.ajax的一種,在.ajax中有一個type屬性,專門用來指定是get請求還是post請求的。如下:  $.ajax({  url:”路徑”,  type:”post/get”,  dataty

混亂不清的概念2——URIURL轉載

參考來源:關於URL跟URI的區別,個人見解 url和uri的概念和區別,網上查了一大通,發現各種回答眼花繚亂,說了等於沒說,本來就是一個很抽象的概念,還用很抽象的的方式來答覆,這不是讓人虐心嗎?經過參考來源作者潛心研究了一番,把他們的區別分享給大家,老鳥勿噴! 1.

MVC,MVP MVVM轉載

1 什麼是MVC MVC的目的是為了把資料(Model)和檢視(View)分離開來,然後用控制器(Controller)作膠水來粘合M和V之間的關係。 這樣做的目的是為了實現注意點分離這樣一個更高層次的設計理念,也就是讓專業的物件做專業的事情,View就只負責檢視相關的東西,Mode

java併發之----原子性,可見性有序性轉載

一、併發程式設計中的三個概念 在併發程式設計中,我們通常會遇到以下三個問題:原子性問題,可見性問題,有序性問題。我們先看具體看一下這三個概念: 1.原子性 原子性:即一個操作或者多個操作 要麼全部執行並且執行的過程不會被任何因素打斷,要麼就都不執行。 一個很經典的例子就是銀行

matlabc++混合程式設計---matlabvs的環境配置問題及方法步驟轉載

matlab和c++混合程式設計---方法和步驟 matlab和c++混合程式設計---matlab和vs的環境配置問題 摘要:Matlab具有很強的數值計算和分析等能力,而C/C++是目前最為流行的高階程式設計語言,兩者互補結合的混合程式設計在科學研究和工程實踐中具有非常重要的意義。從Matlab呼叫C

centos7下mongodb安裝配置 轉載

1、下載安裝包 curl -O https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-3.2.12.tgz 2、解壓 tar -zxvf mongodb-linux-x86_64-3.2.12.tgz

16-Java併發程式設計:TimerTimerTask轉載

Java併發程式設計:Timer和TimerTask(轉載)   下面內容轉載自:   其實就Timer來講就是一個排程器,而TimerTask呢只是一個實現了run方法的一個類,而具體的TimerTask需要由你自己來實現,例如這樣: Timer timer =

Java併發程式設計:TimerTimerTask轉載

public Timer(boolean isDaemon) { this("Timer-" + serialNumber(), isDaemon); }    另外兩個構造方法負責傳入名稱和將timer啟動: public Timer(String name, boo

jar包war包的介紹區別轉載

包括 啟動tomcat 代碼 產品 來源 hive 獲得 到你 apps 來源:https://www.jianshu.com/p/3b5c45e8e5bd 做Java開發,jar包和war包接觸的挺多的,有必要對它們做一個深入的了解,特總結整理如下: 1.jar包的介

SpringBoot:靜態資源的訪問配置轉載

super 工具 webapp adapt ada 目錄 res 優先級 ces 默認靜態資源訪問Spring Boot的默認靜態資源的路徑為: spring.resources.static-locations=classpath:/META-INF/resources/

getClass()getSimpleName()的區別作用轉載

介面: package com.test; public interface Fruit { } 一個實現類: package com.test; public class Apple implements Fruit { } 基本測試類 package com.test; impo