国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

【C#】并行編程實戰(zhàn):任務并行性(上)

這篇具有很好參考價值的文章主要介紹了【C#】并行編程實戰(zhàn):任務并行性(上)。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

?????????本教程對應學習工程:魔術師Dix / HandsOnParallelProgramming · GitCode????????

????????在 .NET 的初始版本中,我們只能依賴線程(線程可以直接創(chuàng)建或者使用 ThreadPool 類創(chuàng)建)。ThreadPool 類提供了一個托管抽象層,但是開發(fā)人員仍然需要依靠 Thread 類來進行更好的控制。而 Thread 類維護困難,且不可托管,給內存和 CPU 帶來沉重負擔。

????????因此,我們需要一種方案,既能充分利用 Thread 類的優(yōu)點,又規(guī)避它的困難。這就是任務 (Task)。

? ? ? ? (另:本章篇幅較大,將分為上種下三部分發(fā)表。)


1、任務(Task)的特性

????????任務(Task)是 .NET 中的抽象,一個異步單位。從技術上講,任務不過是對線程的包裝,并且這個線程還是通過 ThreadPool 創(chuàng)建的。但是任務提供了諸如等待、取消和繼續(xù)之類的特性,這些特性可以在任務完成后運行。

????????任務具有以下重要特性:

  • 任務由 TaskScheduler (任務調度程序)執(zhí)行,默認的調度僅在 ThreadPool 上運行。

  • 可以從任務中返回值。

  • 任務在完成時有通知(ThreadPool 和 Thread 都沒有)。

  • 可以使用 ContinueWith() 構造連續(xù)執(zhí)行的任務。

  • 可以通過調用 Task.Wait() 等待任務的執(zhí)行,這將阻塞調用線程,直到任務完成為止。

  • 與傳統(tǒng)線程或 ThreadPool 相比,任務可以使代碼的可讀性更高。他們還為在 C# 5.0 中引入異步編程構造鋪平了道路。

  • 當一個任務從另一個任務啟動時,可以建立它們之間的父子級關系。

  • 可以將子任務的異常傳播到父任務。

  • 可以使用 CancellationToken 類取消任務。

2、創(chuàng)建和啟動任務

????????我們可以通過多種方式使用任務并行庫(TPL)創(chuàng)建和運行任務。

2.1、使用 Task

????????Task 類是作為 ThreadPool 線程異步執(zhí)行工作的一種方式。它采用的是基于任務的異步模式( Task-Based Asynchronous Pattern,TAP)。非通用 Task 類不會返回結果,因此當需要從任務中返回值時,就需要使用通用版本的 Task<T> 。Task 需要調用 Start 方法來調度運行。

????????具體的 Task 調用代碼如下:

        /// <summary>
        /// 測試方法,打印10次,等待10秒
        /// </summary>
        public static void DebugAndWait()
        {
            int length = 10;
            for (int i = 0; i < length; i++)
            {
                Debug.Log($"執(zhí)行第:{i + 1}/{length} 次打印!");
                Thread.Sleep(1000);
            }
        }
        
        //使用任務執(zhí)行
        private void RunByNewTask()
        {
            //創(chuàng)建任務
            Task task = new Task(TestFunction.DebugAndWait);
            task.Start();//不調用 Start 則不會執(zhí)行
        }

????????最終結果也沒有什么意外:

【C#】并行編程實戰(zhàn):任務并行性(上)

2.2、使用 Task.Factory.StartNew

????????TaskFactory 類的 StartNew 方法也可以創(chuàng)建任務。這種方式創(chuàng)建的任務將安排在 ThreadPool 中執(zhí)行,然后返回該任務的引用:

        private void RunByTaskFactory()
        {
            //使用 Task.Factory 創(chuàng)建任務,不需要調用 Start
            var task = Task.Factory.StartNew(TestFunction.DebugAndWait);
        }

????????當然打印的結果和上述一樣的。

2.3、使用 Task.Run

????????這個原理和 Task.Factory.StartNew 一樣:

        private void RunByTaskRun()
        {
            //使用 Task.Run 創(chuàng)建任務,不需要調用 Start
            var task = Task.Run(TestFunction.DebugAndWait);
        }

2.4、Task.Delay

????????使用 Task.Delay 也可以創(chuàng)建一個任務,但是這個任務有點特別。它可以在指定時間間隔后完成,可以使用

????????CacellationToken 類隨時取消。與 Thread.Sleep 不同,Task.Delay 不需要利用 CPU 周期,且可以異步運行。

????????為了體現(xiàn)兩者的不同,我們直接寫個例子:

        public static void DebugWithTaskDelay()
        {
            Debug.Log("TaskDelay Start");
            Task.Delay(2000);//等待2s        
            Debug.Log("TaskDelay End");
        }

????????然后我們直接在程序中直接同步調用此方法:

        private void RunWithTaskDelay()
        {
            Debug.Log("開始測試 Task.Delay !");
            TestFunction.DebugWithTaskDelay();
            Debug.Log("結束測試 Task.Delay !");
        }

????????結果如下:

【C#】并行編程實戰(zhàn):任務并行性(上)

?????????可以看到4條打印按照順序一瞬間被打印出來了,根本沒有任何等待。而如果我們把上述的 Task.Delay 替換成 Thread.Sleep,結果會如何呢?

【C#】并行編程實戰(zhàn):任務并行性(上)

?????????在運行此方法后,Unity直接卡住,然后2s后打印出4條信息。并且,顯然線程等待生效了,但是是以阻塞主線程的方式生效的。

????????讓我們換回 Task.Delay ,并使用 Task.Run 來運行這個方法,打印結果如下:

【C#】并行編程實戰(zhàn):任務并行性(上)

?????????顯然線程等待命令生效了,說明在子線程中的 Delay 是可以正常工作的。

2.5、Task.Yield

????????Task.Yiled 是創(chuàng)建 await 任務的另一種方法。使用此方法可以讓方法強制變成異步的,并將控制權返回給操作系統(tǒng)。

????????怎么理解呢?我們這里需要一個很耗時的函數(shù):

        public static async void DebugWithTaskYield()
        {
            int length = 27;//這個方法不能執(zhí)行很多次
            string str = "";

            for (int i = 0; i < length; i++)
            {
                //以下是耗時函數(shù)
                str += "1,1";
                var arr = str.Split(',');
                foreach (var item in arr)
                {
                    str += item;
                }

                await Task.Yield();
                Debug.Log($"執(zhí)行第:{i + 1}/{length} 次打??!");
            }
        }

????????這里我直接用簡單的字符串拼接來實現(xiàn)了耗時函數(shù)。

????????我們在主線程調用 Task.Run 來執(zhí)行,Debug 的結果如下:

【C#】并行編程實戰(zhàn):任務并行性(上)

?????????可以看到隨著字符串的增加,單次耗時越來越長。但是無論單次耗時時長有多少,都沒有阻礙主線程!可能大家第一感覺和 Unity 的協(xié)程是一樣的,但是 Unity 的協(xié)程使用是在主線程運行的,使用協(xié)程并不代表不會阻塞主線程。這里我們直接將這段代碼用協(xié)程的邏輯實現(xiàn):

        public static IEnumerator DebugWithCoroutine()
        {
            int length = 27;//這個方法不能執(zhí)行很多次
            string str = "";

            for (int i = 0; i < length; i++)
            {
                //以下是耗時函數(shù)
                str += "1,1";
                var arr = str.Split(',');
                foreach (var item in arr)
                {
                    str += item;
                }

                yield return null;
                Debug.Log($"執(zhí)行第:{i + 1}/{length} 次打??!");
            }
        }

????????邏輯上沒有任何區(qū)別,就是把 await Task.Yield(); 改成了 yield return null 。當然,日志打印上看起來差不多,但是對主線程而言有本質區(qū)別。當運行到后面時,每次迭代都會造成主線程的卡頓。這一點在 Profiler 上看起來非常明顯:

【C#】并行編程實戰(zhàn):任務并行性(上)

?(可以看到協(xié)程調用的顯然耗時)

2.6、Task.FromResult

????????FromResult<T> 是在 .NET Framework 4.5 中才被引入的方法,這在 Unity 2022.2.5 f1c1 使用的 .NET Standard 2.1 是支持的。

        public static int FromResultTest()
        {
            int length = 100;
            int result = 0;
            for (int i = 0; i < length; i++)
                result += Random.Range(0, 100);
            Debug.Log($"FromResultTest 運算結果:{result} ");
            return result;
        }
        
        private void RunWithFromResult()
        {
            Debug.Log("RunWithFromResult Start !");
            Task<int> resultTask = Task.FromResult<int>(TestFunction.FromResultTest());
            Debug.Log("RunWithFromResult End ! Result : " + resultTask.Result);
        }

????????如上述代碼所示 RunWithFromResult 的結果如下:

【C#】并行編程實戰(zhàn):任務并行性(上)

?????????與一般的Task異步不同,這里是按照執(zhí)行順序依次打印的。如果這個函數(shù)是個耗時函數(shù),會阻塞主線程嗎?我把 2.5 里測試的耗時函數(shù)搬過來測試了一下(就不貼代碼了):

【C#】并行編程實戰(zhàn):任務并行性(上)

?????????顯然已經阻塞主線程了。

????????也就是說這個 FromResult 將異步的方法拿到主線程中調度了(也可以理解為把子線程直接拿到父線程)。既然已經是 Unity 主線程了,那么 Task.Delay 就不會生效;而 Thread.Sleep 會生效,且會阻塞主線程。

????????與前面的幾個創(chuàng)建Task任務的方法不同,這個Task.FromResult 是可以調用帶參函數(shù)的(Task.Run 只能運行無參函數(shù))。但即便如此,因為其會阻塞父線程,也不建議在 Unity 主線程中使用。

2.7、Task.FromException 和 Task.FromException<T>

????????這兩個方法都可以拋出異步任務中的異常,在單元測試中很有用。

????????(這里暫時不會用到,就先不講了,在后面學單元測試的時候再詳細學習這兩個)

2.8、Task.FromCanceled 和 Task.FromCanceled<T>

????????????????這個和 Task.FromException 的情況有點類似,都是看起來不知道有啥用其實很有用的方法。為了方便學習,這里還是展開講講。

????????首先看下面一段代碼,這個也是 Task.FromCanceled 的示例代碼:

CancellationTokenSource source = new CancellationTokenSource();//構建取消令牌源
source.Cancel();//設置為取消

//返回標記為取消的任務。
//注意!使用此方法要確保 CancellationTokenSource 已經調用過 Cancel 方法 ,否則會出錯!
Task.FromCanceled(source.Token);

????????當我們把這個最后得到的Task狀態(tài)(Task.Status)打印出來,其結果是便是 Created 。

????????肯定就有人會問了,這個有啥用???我是創(chuàng)建了一個取消的任務?那我執(zhí)行這段代碼的意義是什么呢?

????????單看這段代碼,確實沒什么意義,但是我們這里提出一個需求:

【C#】并行編程實戰(zhàn):任務并行性(上)

?????????邏輯很簡單,但是問題就出在最后,要維護一個Task。我們假設預計執(zhí)行的任務A是某個長期的異步函數(shù),外部需要檢測他的狀態(tài)和結果。那我們在輸入偶數(shù)的時候,該返回什么呢?首先肯定不能返回一個空的Task,這個返回就和正常的Task一樣的了,外部監(jiān)控的狀態(tài)要么是 WaitingToRun, 要么就是 RanToCompletion,要么就是 Running 。我根本無法知道我是執(zhí)行了 任務A 還是沒有執(zhí)行 任務A。

????????這時候就發(fā)現(xiàn) Task.FromCanceled 的作用了:

        private void RunWithFromCanceled()
        {
            var val = commonPanel.GetInt32Parameter();
            //這里測試輸入雙數(shù)就取消執(zhí)行,單數(shù)就正常執(zhí)行。
            CancellationTokenSource source = new CancellationTokenSource();
            if (val % 2 == 0)
                source.Cancel();
            var task = TestFunction.TestCanceledTask(source);
            Debug.Log($"Task State 1: {task.Status}");
        }
        
        /// <summary>
        /// 測試用于取消任務
        /// </summary>
        public static Task TestCanceledTask(CancellationTokenSource source)
        {
            if (source.IsCancellationRequested)
            {
                Debug.Log($"任務取消 !");
                var token = source.Token;       
                return Task.FromCanceled(token);
            }
            else
            {
                Debug.Log($"任務執(zhí)行 !");
                return Task.Run(DebugWithTaskDelay);
            }
        }

????????當輸入偶數(shù)時,就會返回一個已取消的任務,而奇數(shù)則會正常執(zhí)行。

????????當我們對任務進行了封裝,內部的判斷邏輯會比較復雜,而外部也只需要知道任務執(zhí)行情況而不需要知道其內部邏輯。此時使用 Task.FromCanceled 和 Task.FromException 就能返回給外部一個通用的“異?!盩ask。

3、從完成的任務中獲取結果

????????任務并行庫(TPL)中提供的API有如下幾個:

        /// <summary>
        /// 獲取任務并行結果
        /// </summary>
        private void GetTaskResult()
        {
            int inputParam = commonPanel.GetInt32Parameter();
            Debug.Log($"get task result start ! paramter :  {inputParam}");

            //方法1 :new Task
            var task_1 = new Task<int>(()=>TestFunction.FromResultTest(inputParam));
            task_1.Start();
            Debug.Log($"task_1 result : {task_1.Result}");

            //方法2:Task.Factory
            var task_2 = Task.Factory.StartNew<int>(()=> TestFunction.FromResultTest(inputParam));
            Debug.Log($"task_2 result : {task_2.Result}");

            //方法3:
            var task_3 = Task.Run<int>(()=>TestFunction.FromResultTest(inputParam));
            Debug.Log($"task_3 result : {task_3.Result}");

            //方法4:
            var task_4 = Task.FromResult<int>(TestFunction.FromResultTest(inputParam));
            Debug.Log($"task_4 result : {task_4.Result}");
        }

????????這次測試終于出現(xiàn)了一個熟悉的錯誤:

【C#】并行編程實戰(zhàn):任務并行性(上)

?????????Random.Range 只能在Unity主線程使用。

????????這個以前就知道 UnityEngine 的類不能在子線程使用,這里遇到了。但是沒關系,我們直接修改這個方法即可,用System的Random就行了。

????????但是這能說明我們的程序確實在子線程運行了,但是實際上這4個方法都是會阻塞主線程的!

【C#】并行編程實戰(zhàn):任務并行性(上)

?????????所有的運算流程都是和 2.6 的 FromResult 一樣,已經將子線程調回主線程使用了。顯然這幾種方法都是提供一種同步的結果獲取,而真正做到異步計算還不能直接這么使用。


????????限于篇幅,任務并行性(上)到此為止。

? ? ? ? 本教程對應學習工程:魔術師Dix / HandsOnParallelProgramming · GitCode文章來源地址http://www.zghlxwxcb.cn/news/detail-484877.html

到了這里,關于【C#】并行編程實戰(zhàn):任務并行性(上)的文章就介紹完了。如果您還想了解更多內容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。如若轉載,請注明出處: 如若內容造成侵權/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經查實,立即刪除!

領支付寶紅包贊助服務器費用

相關文章

  • C# 任務并行類庫Parallel調用示例

    C# 任務并行類庫Parallel調用示例

    Task Parallel Library 是微軟.NET框架基礎類庫(BCL)中的一個,主要目的是為了簡化并行編程,可以實現(xiàn)在不同的處理器上并行處理不同任務,以提升運行效率。Parallel常用的方法有For/ForEach/Invoke三個靜態(tài)方法。

    2024年02月04日
    瀏覽(19)
  • C# 消息隊列、多線程、回滾、并行編程、異步編程、反射

    消息隊列是一種在應用程序之間傳遞消息的異步通信機制。它可以使應用程序解耦并提高系統(tǒng)的可伸縮性和可靠性。在 C# 中,你可以使用多個消息隊列技術,其中一種廣泛使用的技術是 RabbitMQ。 RabbitMQ 是一個開源的消息代理,實現(xiàn)了高級消息隊列協(xié)議(AMQP),提供了強大的

    2024年01月17日
    瀏覽(20)
  • THRUST:一個開源的、面向異構系統(tǒng)的并行編程語言:編程模型主要包括:數(shù)據(jù)并行性、任務并行性、內存管理、內存訪問控制、原子操作、同步機制、錯誤處理機制、混合編程模型、運行時系統(tǒng)等

    作者:禪與計算機程序設計藝術 https://github.com/NVIDIA/thrust 2021年8月,當代科技巨頭Facebook宣布其開發(fā)了名為THRUST的高性能計算語言,可用于在設備、集群和云環(huán)境中進行并行計算。它具有“易于學習”、“簡單易用”等特征,正在逐步取代C++、CUDA、OpenCL等傳統(tǒng)編程模型,成為

    2024年02月07日
    瀏覽(26)
  • 大數(shù)據(jù)學習(18)-任務并行度優(yōu)化

    大數(shù)據(jù)學習(18)-任務并行度優(yōu)化

    大數(shù)據(jù)學習 ??系列專欄: ??哲學語錄: 承認自己的無知,乃是開啟智慧的大門 ??如果覺得博主的文章還不錯的話,請點贊??+收藏??+留言??支持一下博主哦?? 對于一個分布式的計算任務而言,設置一個合適的并行度十分重要。Hive的計算任務由MapReduce完成,故并行度的

    2024年02月07日
    瀏覽(20)
  • 基于C#編程建立泛型Matrix數(shù)據(jù)類型及對應處理方法

    基于C#編程建立泛型Matrix數(shù)據(jù)類型及對應處理方法

    ????????上一篇文檔中描述了如何寫一個VectorT類,本次在上一篇文檔基礎上,撰寫本文,介紹如何書寫一個泛型Matrix,可以應用于int、double、float等C#數(shù)值型的matrix。 ????????本文所描述的MatrixT是一個泛型,具有不同數(shù)值類型Matrix矩陣構造、新增、刪除、查詢、更改、

    2024年02月02日
    瀏覽(32)
  • 【深度學習】YOLOv8訓練過程,YOLOv8實戰(zhàn)教程,目標檢測任務SOTA,關鍵點回歸

    【深度學習】YOLOv8訓練過程,YOLOv8實戰(zhàn)教程,目標檢測任務SOTA,關鍵點回歸

    https://github.com/ultralytics/ultralytics 官方教程:https://docs.ultralytics.com/modes/train/ 更建議下載代碼后使用 下面指令安裝,這樣可以更改源碼,如果不需要更改源碼就直接pip install ultralytics也是可以的。 這樣安裝后,可以直接修改yolov8源碼,并且可以立即生效。此圖是命令解釋: 安

    2024年02月10日
    瀏覽(24)
  • Django實戰(zhàn)項目-學習任務系統(tǒng)-任務管理

    Django實戰(zhàn)項目-學習任務系統(tǒng)-任務管理

    接著上期代碼框架,開發(fā)第3個功能,任務管理,再增加一個學習任務表,用來記錄發(fā)布的學習任務的標題和內容,預計完成天數(shù),獎勵積分和任務狀態(tài)等信息。 第一步:編寫第三個功能-任務管理 1,編輯模型文件: ./mysite/study_system/models.py: 2,編輯urls配置文件: ./mysite/stu

    2024年02月06日
    瀏覽(26)
  • 【c#】Quartz開源任務調度框架學習及練習Demo

    【c#】Quartz開源任務調度框架學習及練習Demo

    Quartz是一個開源的任務調度框架,作用是支持開發(fā)人員可以定時處理業(yè)務,比如定時發(fā)布郵件等定時操作。 Quartz大致可以分為四部分,但是按功能分的話三部分就可以:schedule(調度器是schedule的一個調度單元)、job(任務)、Trigger(觸發(fā)器) scedule功能:統(tǒng)籌任務調度, JOB:實現(xiàn)

    2024年02月08日
    瀏覽(21)
  • Django實戰(zhàn)項目-學習任務系統(tǒng)-定時任務管理

    Django實戰(zhàn)項目-學習任務系統(tǒng)-定時任務管理

    接著上期代碼框架,開發(fā)第4個功能,定時任務管理,再增加一個學習定時任務表,主要用來設置周期重復性的學習任務,定時周期,定時時間,任務標題和內容,預計完成天數(shù),獎勵積分和任務狀態(tài)等信息。 現(xiàn)實中學習一門課程或一項技能知識,需要很長時間的學習積累才

    2024年02月08日
    瀏覽(16)
  • SpringBoot異步任務及并行事務實現(xiàn)

    SpringBoot異步任務及并行事務實現(xiàn)

    ? ? ? ? 上一篇介紹了原生Java如何實現(xiàn)串行/并行任務,主要使用了線程池 + Future + CountDownLatch,讓主線程等待子線程返回后再向下進行。而在SpringBoot中,利用@Async和AOP對異步任務提供了更加便捷的支持,下面就針對SpringBoot使用異步任務需要注意的細節(jié)做一些分析。 ? ? ?

    2024年02月02日
    瀏覽(18)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領取紅包,優(yōu)惠每天領

二維碼1

領取紅包

二維碼2

領紅包