多線程編程學習筆記——任務並行庫(三)

来源:http://www.cnblogs.com/chillsrc/archive/2017/12/06/7993492.html
-Advertisement-
Play Games

本示例學習如何實現基於Task的非同步操作進行取消流程,以及在任務真正運行前如何知道任務已經被取消。 我們學習如何在task中拋出不同情況的異常,以及如何獲取這些異常信息。 ...


接上文 多線程編程學習筆記——任務並行庫(一)

接上文 多線程編程學習筆記——任務並行庫(二)

 

六、   實現取消選項

          本示例學習如何實現基於Task的非同步操作進行取消流程,以及在任務真正運行前如何知道任務已經被取消。

1.代碼如下:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks; 

namespace ThreadTPLDemo
{   

    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine(" 將Task中實現取消操作。。。");
            var cts =new CancellationTokenSource();

            var task1 = new Task<int>(() => RunTask("任務 1",10, cts.Token),cts.Token);     

                     Console.WriteLine(" ——task1 狀態—{0}", task1.Status);

            cts.Cancel();
                     Console.WriteLine(" ——取消——task1 狀態—{0}—",task1.Status);            

                     Console.WriteLine(" ——task1 在出錯之前 取消了操作—");

            //task1.Start();
            cts = new CancellationTokenSource();
            var task2 = new Task<int>(() => RunTask("任務 2", 10, cts.Token),cts.Token);
            task2.Start();
            for (int i = 0; i < 5; i++)
            {

                Thread.Sleep(500);
                Console.WriteLine(" ——task2 狀態—{0}", task2.Status);
            }

            cts.Cancel();
            for (int i = 0; i < 5; i++)
            {
                Thread.Sleep(500); 
                Console.WriteLine(" ——task2 狀態—{0}", task2.Status);

            }
            Console.WriteLine(" ——任務Task 運行結果—{0}", task2.Result);
            Thread.Sleep(2000);      
            Console.Read(); 

        }
 

        private static int RunTask(string name,int seconds,CancellationToken token)
        {      

            Console.WriteLine("Task {0}  運行線上程={1}中,是否線上程池 :{2}",name,
Thread.CurrentThread.ManagedThreadId,Thread.CurrentThread.IsThreadPoolThread);
for (int i = 0; i < seconds; i++) { Thread.Sleep(TimeSpan.FromSeconds(1)); if (token.IsCancellationRequested) { //取消操作,返回-1; return -1; } } return 42 * seconds; } } }

 

2.程式運行結果如下圖。


      首先我們來看task1的創建代碼,我們給底層任務傳遞一次取消標誌,然後給任務的構造函數又傳遞了一次。

      那為什麼要傳遞兩次取消標誌呢?

      因為如果在task實際啟動之前取消它,則TPL的底層有責任處理這個取消操作。經過TPL底層處理過取消操作的task,如果再次啟動,則會拋出異常。如下圖。

 

 

         然後需要我們自己寫代碼處理取消操作,在取消操作之後,任務的狀態仍然是RanToCompletion,從TPL來角度來講,這個task已經完成。

 

七、   處理task中的異常

          通過此示例我們學習如何在task中拋出不同情況的異常,以及如何獲取這些異常信息。

 1.程式代碼如下:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
 

namespace ThreadTPLDemo
{

    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine(" 處理Task中的異常信息。。。。。");
            try
            {
                var task1 = Task.Run(() => RunTask("任務 1", 2));

                int result = task1.Result;
                Console.WriteLine(" ——task1 狀態—{0}---值=={1}", task1.Status,result);
            }
            catch (Exception ex)
            {

                Console.WriteLine(" ——task1 錯誤信息—{0};innerException--{1}", ex.Message,
ex.InnerException==null?string.Empty:ex.InnerException.Message); } Console.WriteLine(" ——————————————————————"); try { var task2 = Task.Run(() => RunTask("任務 2", 2)); int result = task2.GetAwaiter().GetResult(); Console.WriteLine(" ——task2 狀態—{0}---值=={1}", task2.Status, result); } catch (Exception ex) { Console.WriteLine(" ——task2 錯誤信息—{0}", ex.Message); } Console.WriteLine(" ——————————————————————"); var task3 = new Task<int>(() => RunTask("任務 3", 2)); var task4 = new Task<int>(() => RunTask("任務 4", 2)); var completeTaskAll = Task.WhenAll(task3, task4); var exception = completeTaskAll.ContinueWith(t => Console.WriteLine(" ——task 錯誤信息—{0}", t.Exception)
, TaskContinuationOptions.OnlyOnFaulted); task3.Start(); task4.Start(); Thread.Sleep(
7000); Console.Read(); } private static int RunTask(string name,int seconds) { Console.WriteLine("Task {0} 運行線上程={1}中,是否線上程池 :{2}",name,
Thread.CurrentThread.ManagedThreadId,Thread.CurrentThread.IsThreadPoolThread); Thread.Sleep(TimeSpan.FromSeconds(seconds));
throw new Exception("測試錯誤信息!"); return 42 * seconds; } } }

 

2.程式運行結果,如下圖。

 

         當程式啟動時,創建一個任務task1並嘗試同步獲取結果。Result屬性的Get部分會使當前線程等待直到這個任務完成,並將異常傳播給當前線程。在這種情況下,通過catch代碼塊可以很容易地捕捉異常,不過這個異常是封裝異常。所以可以訪問InnerException來獲取異常信息。

         Task2使用GetAwaiter與GetResult來獲取任務結果。這種情況下,不需要封裝異常,TPL會提取異常。如果底層只有一個task,一次只提取一個異常。

最後一個示例是兩個任務(task3,task4)拋出異常的情況 。通過後續操作來處理異常,只有之前的任務完成之前有異常,這個後續操作才會被觸發 。通過後續操作傳遞TaskContinuationOption.OnlyOrFaulted選項來實現 ,在拋出的異常中封裝了兩個異常。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 使用synchronized雖然能夠避免不同步的現象出現,但是也會出現弊端,比如代碼執行時間過長,那麼其他線程就必須等待該線程執行完畢釋放鎖之後才能拿到鎖。 面對這種問題可以使用同步代碼塊來解決。 2.2.1synchronized方法的弊端: 任務類: 工具類: 線程代碼1: 線程代碼2: 執行代 ...
  • 基類中的某個函數只與部分(並非全部)子類有關。將這個函數移到相關的那些子類去。 ...
  • 今天再學習一些C#的基礎知識,如對 Int Array進行排序:你可以在控制台應用程式中,創建一個類別,它屬性和2個構造函數: class Af { private int[] myVar; public int[] MyIntArray { get { return myVar; } set { ...
  • 第一種:ROW_NUMBER() OVER()方式 select * from ( select *, ROW_NUMBER() OVER(Order by ArtistId ) AS RowId from ArtistModels ) as b where RowId between 10 and ...
  • 一、簡介 之前也記錄過一篇關於把 HTML 文本或 HTML 文件轉換為 PDF 的博客,只是之前那種方法有些局限性。 後來又瞭解到 wkhtmltopdf.exe 這個工具,這個工具比起之前的那種方法簡直是太好用了。它是一個使用 Qt WebKit 引擎做渲染的,能夠把 HTML 文檔轉換成 PD ...
  • 之前一直使用Enum.Parse()將字元串轉為枚舉,沒有深究,後面發現一個問題後對下麵的Enum有了一個初步研究(.net 4.0).看下麵代碼. 首先定義一個test枚舉 結論,對於Enum.Parse() 方法,即使是想通過TryParse()方法判斷返回的bool值,也建議首先使用Enum. ...
  • 原始數據: 要處理為: 最終處理為: 好吧,我們創建一個類: class Ae { private string _InputValue; private char _Delimiter; public Ae(string inputValue, char delimiter) { this._In ...
  • 序列化簡單的說就是把對象的位元組序列永久的保存到硬碟上,但是一些文件操作類也能實現把對象保存到本地(文件流保存XML文件),在存儲對象的結果上是沒有什麼差別的(序列化能保存對象的類型[pototype],而文件操作不能),只不過最後文件類型不同,但是在把對象保存到本地後想對對象在進行操作就有很大差別了 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...