a毛片毛费观看-a毛片在线-a毛片在线观看-a毛片在线免费观看-国产成人综合洲欧美在线-国产成人综合高清在线观看

始創于2000年 股票代碼:831685
咨詢熱線:0371-60135900 注冊有禮 登錄
  • 掛牌上市企業
  • 60秒人工響應
  • 99.99%連通率
  • 7*24h人工
  • 故障100倍補償
您的位置: 網站首頁 > 幫助中心>文章內容

細說多線程(七) —— 并行編程與PLINQ

發布時間:  2012/9/16 6:38:20

目錄

一、線程的定義

二、線程的基礎知識

三、以ThreadStart方式實現多線程

四、CLR線程池的工作者線程

五、CLR線程池的I/O線程

六、異步 SqlCommand

七、并行編程與PLINQ

八、計時器與鎖

 

七、并行編程與PLINQ

要使用多線程開發,必須非常熟悉Thread的使用,而且在開發過程中可能會面對很多未知的問題。為了簡化開發,.NET 4.0 特別提供一個并行編程庫System.Threading.Tasks,它可以簡化并行開發,你無需直接跟線程或線程池打交道,就可以簡單建立多線程應用 程序。此外,.NET還提供了新的一組擴展方法PLINQ,它具有自動分析查詢功能,如果并行查詢能提高系統效率,則同時運行,如果查詢未能從并行查詢中 受益,則按原順序查詢。下面將詳細介紹并行操作的方式。

 

7.1 泛型委托

使用并行編程可以同時操作多個委托,在介紹并行編程前先簡單介紹一下兩個泛型委托System.Func<>與System.Action<>。

Func<>是一個能接受多個參數和一個返回值的泛型委托,它能接受0個到4個輸入參數, 其中 T1,T2,T3,T4 代表自定的輸入類型,TResult為自定義的返回值。
public delegate TResult Func<TResult>()
public delegate TResult Func<T1,TResult>(T1 arg1)
public delegate TResult Func<T1,T2, TResult>(T1 arg1,T2 arg2)
public delegate TResult Func<T1,T2, T3, TResult>(T1 arg1,T2 arg2,T3 arg3)
public delegate TResult Func<T1,T2, T3, ,T4, TResult>(T1 arg1,T2 arg2,T3 arg3,T4 arg4)

Action<>與Func<>十分相似,不同在于Action<>的返回值為void,Action能接受1~16個參數
public delegate void Action<T1>()
public delegate void Action<T1,T2>(T1 arg1,T2 arg2)
public delegate void Action<T1,T2, T3>(T1 arg1,T2 arg2, T3 arg3)
.............
public delegate void Action<T1,T2, T3, ,T4, ...... ,T16>(T1 arg1,T2 arg2,T3 arg3,T4 arg4,...... ,T16 arg16)

 

7.2 任務并行庫(TPL)

System.Threading.Tasks中的類被統稱為任務并行庫(Task Parallel Library,TPL),TPL使用CLR線程池把工作分配到CPU,并能自動處理工作分區、線程調度、取消支持、狀態管理以及其他低級別的細節操作,極大地簡化了多線程的開發。

注意:TPL比Thread更具智能性,當它判斷任務集并沒有從并行運行中受益,就會選擇按順序運行。但并非所有的項目都適合使用并行開發,創建過多并行任務可能會損害程序的性能,降低運行效率。

TPL包括常用的數據并行與任務并行兩種執行方式:

7.2.1 數據并行

數據并行的核心類就是System.Threading.Tasks.Parallel,它包含兩個靜態方法 Parallel.For 與 Parallel.ForEach, 使用方式與for、foreach相仿。通過這兩個方法可以并行處理System.Func<>、 System.Action<>委托。

以下一個例子就是利用 public static ParallelLoopResult For( int from, int max, Action<int>) 方法對List<Person>進行并行查詢。
假設使用單線程方式查詢3個Person對象,需要用時大約6秒,在使用并行方式,只需使用2秒就能完成查詢,而且能夠避開Thread的繁瑣處理。

 1     class Program
 2     {
 3         static void Main(string[] args)
 4         {
 5             //設置最大線程數
6 ThreadPool.SetMaxThreads(1000, 1000); 7 //并行查詢
8 Parallel.For(0, 3,n => 9 { 10 Thread.Sleep(2000); //模擬查詢 11 ThreadPoolMessage(GetPersonList()[n]); 12 }); 13 Console.ReadKey(); 14 } 15 16 //模擬源數據
17 static IList<Person> GetPersonList() 18 { 19 var personList = new List<Person>(); 20 21 var person1 = new Person(); 22 person1.ID = 1; 23 person1.Name = "Leslie"; 24 person1.Age = 30; 25 personList.Add(person1); 26 ........... 27 return personList; 28 } 29 30 //顯示線程池現狀
31 static void ThreadPoolMessage(Person person) 32 { 33 int a, b; 34 ThreadPool.GetAvailableThreads(out a, out b); 35 string message = string.Format("Person ID:{0} Name:{1} Age:{2}\n" + 36 " CurrentThreadId is {3}\n WorkerThreads is:{4}" + 37 " CompletionPortThreads is :{5}\n", 38 person.ID, person.Name, person.Age, 39 Thread.CurrentThread.ManagedThreadId, a.ToString(), b.ToString()); 40 41 Console.WriteLine(message); 42 } 43 }

觀察運行結果,對象并非按照原排列順序進行查詢,而是使用并行方式查詢。

 

若想停止操作,可以利用ParallelLoopState參數,下面以ForEach作為例子。
public static ParallelLoopResult ForEach<TSource>( IEnumerable<TSource> source, Action<TSource, ParallelLoopState> action)
其中source為數據 集,在Action<TSource,ParallelLoopState>委托的ParallelLoopState參數當中包含有 Break()和 Stop()兩個方法都可以使迭代停止。Break的使用跟傳統for里面的使用方式相似,但因為處于并行處理當中,使用Break并不能保證所有運行能 立即停止,在當前迭代之前的迭代會繼續執行。若想立即停止操作,可以使用Stop方法,它能保證立即終止所有的操作,無論它們是處于當前迭代的之前還是之 后。

     class Program
     {
          static void Main(string[] args)
          {
              //設置最大線程數
ThreadPool.SetMaxThreads(1000, 1000); //并行查詢
Parallel.ForEach(GetPersonList(), (person, state) => { if (person.ID == 2) state.Stop(); ThreadPoolMessage(person); }); Console.ReadKey(); } //模擬源數據
static IList<Person> GetPersonList() { var personList = new List<Person>(); var person1 = new Person(); person1.ID = 1; person1.Name = "Leslie"; person1.Age = 30; personList.Add(person1); .......... return personList; } //顯示線程池現狀
static void ThreadPoolMessage(Person person) { int a, b; ThreadPool.GetAvailableThreads(out a, out b); string message = string.Format("Person ID:{0} Name:{1} Age:{2}\n" + " CurrentThreadId is {3}\n WorkerThreads is:{4}" + " CompletionPortThreads is :{5}\n", person.ID, person.Name, person.Age, Thread.CurrentThread.ManagedThreadId, a.ToString(), b.ToString()); Console.WriteLine(message); } }

觀察運行結果,當Person的ID等于2時,運行將會停止。

 

當要在多個線程中調用本地變量,可以使用以下方法:
public static ParallelLoopResult ForEach<TSource, TLocal>(IEnumerable<Of TSource>, Func<Of TLocal>, Func<Of TSource,ParallelLoopState,TLocal,TLocal>, Action<Of TLocal>)
其中第一個參數為數據集;
第二個參數是一個Func委托,用于在每個線程執行前進行初始化;
第 三個參數是委托Func<Of T1,T2,T3,TResult>,它能對數據集的每個成員進行迭代,當中T1是數據集的成員,T2是一個ParallelLoopState對 象,它可以控制迭代的狀態,T3是線程中的本地變量;
第四個參數是一個Action委托,用于對每個線程的最終狀態進行最終操作。

在以下例子中,使用ForEach計算多個Order的總體價格。在ForEach方法中,首先把參數初始化為0f,然后用把同一個Order的多 個OrderItem價格進行累加,計算出Order的價格,最后把多個Order的價格進行累加,計算出多個Order的總體價格。

 1     public class Order
 2     {
 3         public int ID;
 4         public float Price;
 5     }
 6 
 7     public class OrderItem
 8     {
 9         public int ID;
10         public string Goods;
11         public int OrderID;
12         public float Price;
13         public int Count;
14     }
15 
16     class Program
17     {
18         static void Main(string[] args)
19         {
20             //設置最大線程數
21 ThreadPool.SetMaxThreads(1000, 1000); 22 float totalPrice = 0f; 23 //并行查詢
24 var parallelResult = Parallel.ForEach(GetOrderList(), 25 () => 0f, //把參數初始值設為0
26 (order, state, orderPrice) => 27 { 28 //計算單個Order的價格
29 orderPrice = GetOrderItem().Where(item => item.OrderID == order.ID) 30 .Sum(item => item.Price * item.Count); 31 order.Price = orderPrice; 32 ThreadPoolMessage(order); 33 34 return orderPrice; 35 }, 36 (finallyPrice) => 37 { 38 totalPrice += finallyPrice;//計算多個Order的總體價格
39 } 40 ); 41 42 while (!parallelResult.IsCompleted) 43 Console.WriteLine("Doing Work!"); 44 45 Console.WriteLine("Total Price is:" + totalPrice); 46 Console.ReadKey(); 47 } 48 //虛擬數據 49 static IList<Order> GetOrderList() 50 { 51 IList<Order> orderList = new List<Order>(); 52 Order order1 = new Order(); 53 order1.ID = 1; 54 orderList.Add(order1); 55 ............ 56 return orderList; 57 } 58 //虛擬數據 59 static IList<OrderItem> GetOrderItem() 60 { 61 IList<OrderItem> itemList = new List<OrderItem>(); 62 63 OrderItem orderItem1 = new OrderItem(); 64 orderItem1.ID = 1; 65 orderItem1.Goods = "iPhone 4S"; 66 orderItem1.Price = 6700; 67 orderItem1.Count = 2; 68 orderItem1.OrderID = 1; 69 itemList.Add(orderItem1); 70 ........... 71 return itemList; 72 } 73 74 //顯示線程池現狀
75 static void ThreadPoolMessage(Order order) 76 { 77 int a, b; 78 ThreadPool.GetAvailableThreads(out a, out b); 79 string message = string.Format("OrderID:{0} OrderPrice:{1}\n" + 80 " CurrentThreadId is {2}\n WorkerThreads is:{3}" + 81 " CompletionPortThreads is:{4}\n", 82 order.ID, order.Price, 83 Thread.CurrentThread.ManagedThreadId, a.ToString(), b.ToString()); 84 85 Console.WriteLine(message); 86 } 87 }

運行結果

 

 7.2.2 任務并行

在TPL當中還可以使用Parallel.Invoke方法觸發多個異步任務,其中 actions 中可以包含多個方法或者委托,parallelOptions用于配置Parallel類的操作。
public static void Invoke(Action[] actions )
public static void Invoke(ParallelOptions parallelOptions, Action[] actions )
下面例子中利用了Parallet.Invoke并行查詢多個Person,actions當中可以綁定方法、lambda表達式或者委托,注意綁定方法時必須是返回值為void的無參數方法。

     class Program
     {
         static void Main(string[] args)
         {
             //設置最大線程數
ThreadPool.SetMaxThreads(1000, 1000); //任務并行
Parallel.Invoke(option, PersonMessage, ()=>ThreadPoolMessage(GetPersonList()[1]), delegate(){ ThreadPoolMessage(GetPersonList()[2]); }); Console.ReadKey(); } static void PersonMessage() { ThreadPoolMessage(GetPersonList()[0]); } //顯示線程池現狀
static void ThreadPoolMessage(Person person) { int a, b; ThreadPool.GetAvailableThreads(out a, out b); string message = string.Format("Person ID:{0} Name:{1} Age:{2}\n" + " CurrentThreadId is {3}\n WorkerThreads is:{4}" + " CompletionPortThreads is :{5}\n", person.ID, person.Name, person.Age, Thread.CurrentThread.ManagedThreadId, a.ToString(), b.ToString()); Console.WriteLine(message); } //模擬源數據
static IList<Person> GetPersonList() { var personList = new List<Person>(); var person1 = new Person(); person1.ID = 1; person1.Name = "Leslie"; person1.Age = 30; personList.Add(person1); .......... return personList; } }

運行結果

 


7.3 Task簡介

以Thread創建的線程被默認為前臺線程,當然你可以把線程IsBackground屬性設置為true,但TPL為此提供了一個更簡單的類Task。
Task存在于System.Threading.Tasks命名空間當中,它可以作為異步委托的簡單替代品。
通過Task的Factory屬性將返回TaskFactory類,以TaskFactory.StartNew(Action)方法可以創建一個新線程,所創建的線程默認為后臺線程。

 1     class Program
 2     {
 3         static void Main(string[] args)
 4         {
 5             ThreadPool.SetMaxThreads(1000, 1000);
 6             Task.Factory.StartNew(() => ThreadPoolMessage());
 7             Console.ReadKey();
 8         }
 9 
10         //顯示線程池現狀
11 static void ThreadPoolMessage() 12 { 13 int a, b; 14 ThreadPool.GetAvailableThreads(out a, out b); 15 string message = string.Format("CurrentThreadId is:{0}\n" + 16 "CurrentThread IsBackground:{1}\n" + 17 "WorkerThreads is:{2}\nCompletionPortThreads is:{3}\n", 18 Thread.CurrentThread.ManagedThreadId, 19 Thread.CurrentThread.IsBackground.ToString(), 20 a.ToString(), b.ToString()); 21 Console.WriteLine(message); 22 } 23 }

運行結果

 

 

若要取消處理,可以利用CancellationTakenSource對象,在TaskFactory中包含有方法
public Task StartNew( Action action, CancellationToken cancellationToken )
在 方法中加入CancellationTakenSource對象的CancellationToken屬性,可以控制任務的運行,調用 CancellationTakenSource.Cancel時任務就會自動停止。下面以圖片下載為例子介紹一下TaskFactory的使用。

服務器端頁面

 <html xmlns="http://www.w3.org/1999/xhtml">
 <head runat="server">
     <title></title>
     <script type="text/C#" runat="server">
private static List<string> url=new List<string>();

protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
url.Clear();
Application["Url"] = null;
}
}

protected void CheckBox_CheckedChanged(object sender, EventArgs e)
{
CheckBox checkBox = (CheckBox)sender;
if (checkBox.Checked)
url.Add(checkBox.Text);
else
url.Remove(checkBox.Text);
Application["Url"]= url;
}
</script> </head> <body> <form id="form1" runat="server" > <div align="left"> <div align="center" style="float: left;"> <asp:Image ID="Image1" runat="server" ImageUrl="~/Images/A.jpg" /><br /> <asp:CheckBox ID="CheckBox1" runat="server" AutoPostBack="True"
oncheckedchanged="CheckBox_CheckedChanged" Text="A.jpg" /> </div> <div align="center" style="float: left"> <asp:Image ID="Image2" runat="server" ImageUrl="~/Images/B.jpg" /><br /> <asp:CheckBox ID="CheckBox2" runat="server" AutoPostBack="True"
oncheckedchanged="CheckBox_CheckedChanged" Text="B.jpg" /> </div> <div align="center" style="float: left"> <asp:Image ID="Image3" runat="server" ImageUrl="~/Images/C.jpg" /><br /> <asp:CheckBox ID="CheckBox3" runat="server" AutoPostBack="True"
oncheckedchanged="CheckBox_CheckedChanged" Text="C.jpg" /> </div> <div align="center" style="float: left"> <asp:Image ID="Image4" runat="server" ImageUrl="~/Images/D.jpg" /><br /> <asp:CheckBox ID="CheckBox4" runat="server" AutoPostBack="True"
oncheckedchanged="CheckBox_CheckedChanged" Text="D.jpg" /> </div> <div align="center" style="float: left"> <asp:Image ID="Image5" runat="server" ImageUrl="~/Images/E.jpg" /><br /> <asp:CheckBox ID="CheckBox5" runat="server" AutoPostBack="True"
oncheckedchanged="CheckBox_CheckedChanged" Text="E.jpg" /> </div> </div> </form> </body> </html>

首先在服務器頁面中顯示多個*.jpg圖片,每個圖片都有對應的CheckBox檢測其選擇情況。
所選擇圖片的路徑會記錄在Application["Url"]當中傳遞到Handler.ashx當中。

注意:Application是一個全局變量,此處只是為了顯示Task的使用方式,在ASP.NET開發應該慎用Application。

Handler.ashx 處理圖片的下載,它從 Application["Url"] 當中獲取所選擇圖片的路徑,并把圖片轉化成byte[]二進制數據。
再把圖片的數量,每副圖片的二進制數據的長度記錄在OutputStream的頭部。
最后把圖片的二進制數據記入 OutputStream 一并輸出。

 1 public class Handler : IHttpHandler 
 2 {
 3     public void ProcessRequest(HttpContext context)
 4     {
 5         //獲取圖片名,把圖片數量寫OutputStream
6 List<String> urlList = (List<string>)context.Application["Url"]; 7 context.Response.OutputStream.Write(BitConverter.GetBytes(urlList.Count), 0, 4); 8 9 //把圖片轉換成二進制數據
10 List<string> imageList = GetImages(urlList); 11 12 //把每副圖片長度寫入OutputStream
13 foreach (string image in imageList) 14 { 15 byte[] imageByte=Convert.FromBase64String(image); 16 context.Response.OutputStream.Write(BitConverter.GetBytes(imageByte.Length),0,4); 17 } 18 19 //把圖片寫入OutputStream
20 foreach (string image in imageList) 21 { 22 byte[] imageByte = Convert.FromBase64String(image); 23 context.Response.OutputStream.Write(imageByte,0,imageByte.Length); 24 } 25 } 26 27 //獲取多個圖片的二進制數據
28 private List<string> GetImages(List<string> urlList) 29 { 30 List<string> imageList = new List<string>(); 31 foreach (string url in urlList) 32 imageList.Add(GetImage(url)); 33 return imageList; 34 } 35 36 //獲取單副圖片的二進制數據
37 private string GetImage(string url) 38 { 39 string path = "E:/My Projects/Example/WebSite/Images/"+url; 40 FileStream stream = new FileStream(path, FileMode.Open, FileAccess.Read); 41 byte[] imgBytes = new byte[10240]; 42 int imgLength = stream.Read(imgBytes, 0, 10240); 43 return Convert.ToBase64String(imgBytes,0,imgLength); 44 } 45 46 public bool IsReusable 47 { 48 get{ return false;} 49 } 50 }

 

客戶端

建立一個WinForm窗口,里面加入一個WebBrowser連接到服務器端的Default.aspx頁面。
當按下Download按鍵時,系統就會利用TaskFactory.StartNew的方法建立異步線程,使用WebRequest方法向Handler.ashx發送請求。
接收到回傳流時,就會根據頭文件的內容判斷圖片的數量與每副圖片的長度,把二進制數據轉化為*.jpg文件保存。

系統利用TaskFactory.StartNew(action,cancellationToken) 方式異步調用GetImages方法進行圖片下載。
當 用戶按下Cancel按鈕時,異步任務就會停止。值得注意的是,在圖片下載時調用了 CancellationToken.ThrowIfCancellationRequested方法,目的在檢查并行任務的運行情況,在并行任務被停止 時釋放出OperationCanceledException異常,確保用戶按下Cancel按鈕時,停止所有并行任務。

     public partial class Form1 : Form
     {
         private CancellationTokenSource tokenSource = new CancellationTokenSource();
         
         public Form1()
         {
             InitializeComponent();
             ThreadPool.SetMaxThreads(1000, 1000);
         }
 
         private void downloadToolStripMenuItem_Click(object sender, EventArgs e)
         {
              Task.Factory.StartNew(GetImages,tokenSource.Token);
         }
 
         private void cancelToolStripMenuItem_Click(object sender, EventArgs e)
         {
             tokenSource.Cancel();
         }
 
         private void GetImages()
         {
             //發送請求,獲取輸出流
WebRequest webRequest = HttpWebRequest.Create("Http://localhost:5800/Handler.ashx"); Stream responseStream=webRequest.GetResponse().GetResponseStream(); byte[] responseByte = new byte[81960]; IAsyncResult result=responseStream.BeginRead(responseByte,0,81960,null,null); int responseLength = responseStream.EndRead(result); //獲取圖片數量
int imageCount = BitConverter.ToInt32(responseByte, 0); //獲取每副圖片的長度
int[] lengths = new int[imageCount]; for (int n = 0; n < imageCount; n++) { int length = BitConverter.ToInt32(responseByte, (n + 1) * 4); lengths[n] = length; } try { //保存圖片
for (int n = 0; n < imageCount; n++) { string path = string.Format("E:/My Projects/Example/Test/Images/pic{0}.jpg", n); FileStream file = new FileStream(path, FileMode.Create, FileAccess.ReadWrite); //計算字節偏移量
int offset = (imageCount + 1) * 4; for (int a = 0; a < n; a++) offset += lengths[a]; file.Write(responseByte, offset, lengths[n]); file.Flush(); //模擬操作
Thread.Sleep(1000); //檢測CancellationToken變化
tokenSource.Token.ThrowIfCancellationRequested(); } } catch (OperationCanceledException ex) { MessageBox.Show("Download cancel!"); } } }


 

7.4 并行查詢(PLINQ)

并行 LINQ (PLINQ) 是 LINQ 模式的并行實現,主要區別在于 PLINQ 嘗試充分利用系統中的所有處理器。 它利用所有處理器的方法,把數據源分成片段,然后在多個處理器上對單獨工作線程上的每個片段并行執行查詢, 在許多情況下,并行執行意味著查詢運行速度顯著提高。但這并不說明所有PLINQ都會使用并行方式,當系統測試要并行查詢會對系統性能造成損害時,那將自動化地使用同步執行。
在System.Linq.ParallelEnumerable類中,包含了并行查詢的大部分方法。

 

方法成員 

說明

AsParallel

PLINQ 的入口點。 指定如果可能,應并行化查詢的其余部分。

AsSequential(Of TSource)

指定查詢的其余部分應像非并行 LINQ 查詢一樣按順序運行。

AsOrdered

指定 PLINQ 應保留查詢的其余部分的源序列排序,直到例如通過使用 orderby(在 Visual Basic 中為 Order By)子句更改排序為止。

AsUnordered(Of TSource)

指定查詢的其余部分的 PLINQ 不需要保留源序列的排序。

WithCancellation(Of TSource)

指定 PLINQ 應定期監視請求取消時提供的取消標記和取消執行的狀態。

WithDegreeOfParallelism(Of TSource)

指定 PLINQ 應當用來并行化查詢的處理器的最大數目。

WithMergeOptions(Of TSource)

提供有關 PLINQ 應當如何(如果可能)將并行結果合并回到使用線程上的一個序列的提示。

WithExecutionMode(Of TSource)

指定 PLINQ 應當如何并行化查詢(即使默認行為是按順序運行查詢)。

ForAll(Of TSource)

多線程枚舉方法,與循環訪問查詢結果不同,它允許在不首先合并回到使用者線程的情況下并行處理結果。

Aggregate 重載

對于 PLINQ 唯一的重載,它啟用對線程本地分區的中間聚合以及一個用于合并所有分區結果的最終聚合函數。


7.4.1 AsParallel

通常想要實現并行查詢,只需向數據源添加 AsParallel 查詢操作即可。

 1     class Program
 2     {
 3         static void Main(string[] args)
 4         {
 5             var personList=GetPersonList().AsParallel() 
 6                    .Where(x=>x.Age>30);
 7             Console.ReadKey();
 8         }
 9 
10         //模擬源數據
11 static IList<Person> GetPersonList() 12 { 13 var personList = new List<Person>(); 14 15 var person1 = new Person(); 16 person1.ID = 1; 17 person1.Name = "Leslie"; 18 person1.Age = 30; 19 personList.Add(person1); 20 ........... 21 return personList; 22 } 23 }

 

7.4.2 AsOrdered

若要使查詢結果必須保留源序列排序方式,可以使用AsOrdered方法。
AsOrdered依然使用并行方式,只是在查詢過程加入額外信息,在并行結束后把查詢結果再次進行排列。

     class Program
     {
         static void Main(string[] args)
         {
             var personList=GetPersonList().AsParallel().AsOrdered()
                 .Where(x=>x.Age<30);
             Console.ReadKey();
         }
 
         static IList<Person> GetPersonList()
         {......}
     }


7.4.3 WithDegreeOfParallelism

默認情況下,PLINQ 使用主機上的所有處理器,這些處理器的數量最多可達 64 個。
通過使用 WithDegreeOfParallelism(Of TSource) 方法,可以指示 PLINQ 使用不多于指定數量的處理器。

 1     class Program
 2     {
 3         static void Main(string[] args)
 4         {
 5             var personList=GetPersonList().AsParallel().WithDegreeOfParallelism(2)
 6                 .Where(x=>x.Age<30);
 7             Console.ReadKey();
 8         }
 9 
10         static IList<Person> GetPersonList()
11         {.........}
12     }

 

7.4.4 ForAll

如果要對并行查詢結果進行操作,一般會在for或foreach中執行,執行枚舉操作時會使用同步方式。
有見及此,PLINQ中包含了ForAll方法,它可以使用并行方式對數據集進行操作。

     class Program
     {
         static void Main(string[] args)
         {
             ThreadPool.SetMaxThreads(1000, 1000);
             GetPersonList().AsParallel().ForAll(person =>{
                 ThreadPoolMessage(person);
             });
             Console.ReadKey();
         }
 
         static IList<Person> GetPersonList()
         {.......}
 
          //顯示線程池現狀
static void ThreadPoolMessage(Person person) { int a, b; ThreadPool.GetAvailableThreads(out a, out b); string message = string.Format("Person ID:{0} Name:{1} Age:{2}\n" + " CurrentThreadId is {3}\n WorkerThreads is:{4}" + " CompletionPortThreads is :{5}\n", person.ID, person.Name, person.Age, Thread.CurrentThread.ManagedThreadId, a.ToString(), b.ToString()); Console.WriteLine(message); } }

運行結果

 

7.4.5 WithCancellation

如果需要停止查詢,可以使用 WithCancellation(Of TSource) 運算符并提供 CancellationToken 實例作為參數。
與 第三節Task的例子相似,如果標記上的 IsCancellationRequested 屬性設置為 true,則 PLINQ 將會注意到它,并停止所有線程上的處理,然后引發 OperationCanceledException。這可以保證并行查詢能夠立即停止。

 1     class Program
 2     {
 3         static CancellationTokenSource tokenSource = new CancellationTokenSource();
 4 
 5         static void Main(string[] args)
 6         {
 7             Task.Factory.StartNew(Cancel);
 8             try
 9             {
10                 GetPersonList().AsParallel().WithCancellation(tokenSource.Token)
11                     .ForAll(person =>
12                     {
13                         ThreadPoolMessage(person);
14                     });
15             }
16             catch (OperationCanceledException ex)
17             { }
18             Console.ReadKey();
19         }
20 
21         //在10~50毫秒內發出停止信號
22 static void Cancel() 23 { 24 Random random = new Random(); 25 Thread.Sleep(random.Next(10,50)); 26 tokenSource.Cancel(); 27 } 28 29 static IList<Person> GetPersonList() 30 {......} 31 32 //顯示線程池現狀
33 static void ThreadPoolMessage(Person person) 34 { 35 int a, b; 36 ThreadPool.GetAvailableThreads(out a, out b); 37 string message = string.Format("Person ID:{0} Name:{1} Age:{2}\n" + 38 " CurrentThreadId is {3}\n WorkerThreads is:{4}" + 39 " CompletionPortThreads is :{5}\n", 40 person.ID, person.Name, person.Age, 41 Thread.CurrentThread.ManagedThreadId, a.ToString(), b.ToString()); 42 Console.WriteLine(message); 43 } 44 } 億恩-天使(QQ:530997) 電話 037160135991 服務器租用,托管歡迎咨詢。

本文出自:億恩科技【www.ibaoshan.net】

服務器租用/服務器托管中國五強!虛擬主機域名注冊頂級提供商!15年品質保障!--億恩科技[ENKJ.COM]

  • 您可能在找
  • 億恩北京公司:
  • 經營性ICP/ISP證:京B2-20150015
  • 億恩鄭州公司:
  • 經營性ICP/ISP/IDC證:豫B1.B2-20060070
  • 億恩南昌公司:
  • 經營性ICP/ISP證:贛B2-20080012
  • 服務器/云主機 24小時售后服務電話:0371-60135900
  • 虛擬主機/智能建站 24小時售后服務電話:0371-60135900
  • 專注服務器托管17年
    掃掃關注-微信公眾號
    0371-60135900
    Copyright© 1999-2019 ENKJ All Rights Reserved 億恩科技 版權所有  地址:鄭州市高新區翠竹街1號總部企業基地億恩大廈  法律顧問:河南亞太人律師事務所郝建鋒、杜慧月律師   京公網安備41019702002023號
      0
     
     
     
     

    0371-60135900
    7*24小時客服服務熱線

     
     
    丰满人妻被中出中文字幕| 免费无码成人AV在线播| 52综合精品国产二区无码| 无码OL丝袜高跟秘书在线观看不| 老头发狂的吸住她的乳尖| 国产成人无码A区在线观看视频免 国产成人无码A区在线观看视频A 国产成人无码A区在线观看视频 | 国产二级一片内射视频播放| 真人无码作爱免费视频| 无码丰满少妇2在线观看| 毛片内射久久久一区| 国产高清一区二区三区视频| 42岁女子20天断崖式衰老| 亚洲A∨无码无在线观看| 欧美最婬乱婬爆婬牲视| 精品人人妻人人澡人人爽人人| 厨房里我扒了岳的内裤| 一个添下面两个吃奶把腿扒开| 同学要做吗PO爱喝花茶的小酥肉| 免费无遮挡毛片中文字幕| 国精一二三区别免费| 尝到了甜头两人每天都会想方设法| 亚洲熟女WWW一区二区三区| 私人小影院久久久影院| 免费无遮挡又黄又爽网站| 国精无码欧精品亚洲一区| 成人国产精品一区二区网站| 永久看一二三四线| 小雪尝禁果又粗又大的中国地图 | 亚洲AV无码成人精品区H| 人人妻人人澡人人爽人人精品| 久久久久99精品成人片三人毛片 | 国产在线视频一区二区三区| 暗交小拗女一区二区三区视频| 亚洲无熟妇成人无码| 婷婷色丁香五月激情综合| 农村野外性BBW| 激情 亚洲 成人小说 激情| 纯爱无遮挡H肉动漫在线播放| 在办公室伦流澡到高潮H| 亚洲 欧美 中文 日韩AⅤ手机| 日本畜禽CORPORATION| 久久综合噜噜激激的五月天| 国产小视频A在线观看| 成人免费午夜无码视频在线播放| 在线观看一区二区三区AV| 亚洲AV成人一区二区三区在线播| 日本丰满人妻熟妇BBBBB| 老熟女多次高潮露脸视频| 国产午夜片无码区在线观看| 成人国产一区二区三区精品不卡| 越看越湿的啪啪的小说免费| 亚洲AV不卡无码国产| 日韩一线无码AV毛片免费| 免费私人家庭影院| 精品国产人成亚洲区| 国产二级一片内射视频插放| かしこまりました中文在线| 一区二区精品视频日本| 亚洲AV图片一亚洲AV| 三妻四妾免费观看完整版高清| 免费拗女网站1300部| 精品国产一区二区AV片| 国产精品成人免费视频网站| 暗交小拗女一区二区三区电影 | 久久久久AV综合网成人| 国产情侣疯狂作爱系列| 处破痛哭A√18成年片免| 7777色鬼XXXX欧美色妇| 亚洲色精品一区二区三区| 性丰满ⅩXXOOOZZXXHD| 色噜噜狠狠色综合久色AⅤ网| 欧美 日韩 国产 成人 在线观看 | 日韩一区二区三区精品视频| 农村寡妇精品一区二区三区| 久久精品国产99精品国产2| 国产乱人伦精品一区二区在线观看| 补课老师让我爽了一夜| 中文字字幕在线乱码| 亚洲色偷拍一区二区三区| 亚洲 小说 欧美 激情 另类| 熟妇人妻AV中文字幕老熟妇| 人妻少妇出轨中文字幕| 男JI大巴进入女人的视频| 久久久久国色AⅤ免费看| 国精产品一区一区三区有限| 国产成人无码A区在线观看视频| 被公疯狂进入的美丽人妻| 3分19秒砍人手脚血腥场面| 亚洲中文字幕精品久久| 亚洲AV综合色一区二区三区| 无码精品人妻一区二区三区网站| 日韩人妻无码一区二区三区| 欧美日韩亚洲国产综合乱| 两个男用舌头到我的蕊花| 精品人妻少妇一区二区三区不卡| 国产三级多多影院| 国产V综合V亚洲欧美久久| 潮喷失禁大喷水AⅤ无码| AV天堂午夜精品一区二区三区| 伊人久久大香线蕉综合影院| 亚洲乱码一区二区三区| 亚洲av成人网站| 图片区小说区另类春色| 日韩欧美AⅤ综合网站发布| 欧美一性一乱一交一视频| 免费人妻AV无码专区| 久久人人爽人人爽AV片| 精品少妇爆乳无码av专用区| 国内精品久久人妻无码不卡| 国产精品免费_区二区三区观看 | 国产农村乱人伦精品视频 | 你真紧你这是要我的命吗什么意思| 久久久久久精品成人网站蜜臀| 婚外偷欢娇妻HD| 国产亚洲大尺度无码无码专线| 国产精品白丝无码ThePorn| 大白屁股白浆XXⅩSS| 把腿张开我要cao死你在线观看 | 成人乱婬AV日日摸夜夜爽| JAPANESE55丰满成熟妇| 52色擼99热99RE超碰| 中日大胆裸体棚拍人体| 亚洲一码和欧洲二码的尺码区别| 亚洲国产精品久久久天堂不卡海量| 性猛交富婆Ⅹ×××乱大交| 无码精品人妻一区二区三区涩爱| 手机成人免费A级毛片无码| 日韩欧美一区二区三区免费观看 | 亚洲欧洲闷骚AV少妇影院| 亚洲AV综合色区无码专区蜜桃| 小宝贝荡货啊用力水湿AⅤ视频| 我和闺蜜在KTV被八人伦| 熟女人妇 成熟妇女系列视频| 日产乱码一二三区别免费下| 人妻人人做人碰人人添| 欧美颜射内射中出口爆在线| 欧美激情内射喷水高潮| 女人不怕粗短就怕蘑菇头什么意| 免费看成人AV片| 美女肛交视频蜜桃国产一二区| 久久影院午夜理论片无码| 久久见久久久国产精品蜜桃| 精品人妻视频一区二区三区 | 国产精品看高国产精品不卡| 国产GAYSEXCHINA男同| 丰满少妇大叫太大太粗| 顶级大但人文艺术巫| 处 女 开 破视频处CT开| 吃奶摸下激烈床震视频试看| 成色好的Y31S标准版| 粗大的内捧猛烈进出视频| 成人无码激情视频在线观看| 成人亚洲欧美在线观看| 成人免费A级毛片无码片在线播放| 才摸两下小奶头就受不了了| 成人精品视频一区二区不卡| 成人无码A区在线观看视频| 大香伊蕉人在播放2019| 绯色AV一区二区三区蜜臀| 高中生被C到爽哭视频| 国产XXX69麻豆国语对白| 国产成人久久777777| 国产精品V欧美精品V日韩精品 | 无码动漫性爽XO视频在线| 无码精品一区二区三区在线| 无码国产精品一区二区免费I6| 无码AV中文字幕久久AV| 无码熟熟妇丰满人妻啪啪喷水| 无码午夜成人1000部免费视频| 午夜精品射精入后重之免费观看| 小诗的公交车日记免费读| 亚洲AV区无码字幕中文色| 亚洲AV中文无码4区| 亚洲国产区男人本色| 亚洲熟妇无码乱子AV| 伊人久久大香线蕉在观看 | 色婷婷AV一区二区三区在线观看| 上司侵犯部下的人妻| 偷窥 间谍 隐 TUBE| 无遮挡亲胸捏胸免费视频| 亚洲AV熟女高潮一区二区| 亚洲精品无码GV在线观看| 要灬要灬再深点受不了好舒服 | 浪潮av专区一区二区三区| 蜜芽亚洲AV无码精品国产| 欧美成人影院亚洲综合图| 人妻丰满熟妞AV无码区| 日欧 片内射AV在线影院| 丝袜一区二区三区在线播放| 无码熟妇人妻AV影音先锋| 亚洲AV综合色区无码二区偷拍 | 在线观看无码H片| 51草莓看视频在线观看免费| WWW.嫩草AV天堂影院| 成人午夜福利电影天堂| 国产成人精品久久一区二区| 国产乱子影视频上线免费观看| 黑人大群体交免费视频| 久久精品丝袜高跟鞋| 美女扒开粉嫩尿口的照片|