一区二区三区三上|欧美在线视频五区|国产午夜无码在线观看视频|亚洲国产裸体网站|无码成年人影视|亚洲AV亚洲AV|成人开心激情五月|欧美性爱内射视频|超碰人人干人人上|一区二区无码三区亚洲人区久久精品

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

什么是Task

汽車電子技術 ? 來源:程序猿知秋 ? 作者: 程序猿知秋 ? 2023-01-20 15:07 ? 次閱讀

什么是Task?

描述

  • Task出現之前,微軟的多線程處理方式有:Thread→ThreadPool→委托的異步調用,雖然可以滿足基本業(yè)務場景,但它們在多個線程的等待處理方面、資源占用方面、延續(xù)和阻塞方面都顯得比較笨拙,在面對復雜的業(yè)務場景下,顯得有點捉襟見肘
  • Task是微軟在.Net 4.0時代推出來的,也是微軟極力推薦的一種多線程的處理方式,Task看起來像一個Thread,實際上,它是在ThreadPool的基礎上進行的封裝
  • Task的控制和擴展性很強,在線程的延續(xù)、阻塞、取消、超時等方面遠勝于Thread和ThreadPool
  • Task可以簡單看作相當于Thead+TheadPool,其性能比直接使用Thread要更好,在工作中更多的是使用Task來處理多線程任務

任務Task和線程Thread的區(qū)別

  • Task是建立在Thread之上的,最終其實還是由Thread去執(zhí)行,它們都是在 System.Threading 命名空間下的
  • Task跟Thread并不是一對一的關系。比如說開啟10個任務并不一定會開啟10個線程,因為使用Task開啟新任務時,是從線程池中調用線程,這點與ThreadPool.QueueUserWorkItem類似

Task的使用

創(chuàng)建Task的三種方式

  • 方式一:通過創(chuàng)建Task對象后調用其 Start()函數
  • 方式二:調用Task的靜態(tài)方法Run()
  • 方式三:通過Task工廠,新建一個線程
// 方式一,通過Start
Task t1 = new Task(() => { Console.WriteLine("我是Task方式一"); });
t1.Start();


// 方式二,通過Run
Task t2= Task.Run(()=>{Console.WriteLine("我是Task方式二"); });


// 方式三,通過工廠
Task t3= Task.Factory.StartNew(()=>{Console.WriteLine("我是Task方式三"); });

帶返回值與不帶返回值的Task

  • Task無返回值: 接收的是Action委托類型
  • Task有返回值: 接收的是Func委托類型
static void Main()
{
  // 沒有返回參數
  Task t1 = new Task(() => { Console.WriteLine("我是Task沒有返回參數"); });
  t1.Start();


  // 有返回參數
  Task<int> t2 = new Task<int>(() => { return 1+1; });
  t2.Start();
  int result = t2.Result;
  Console.WriteLine(result);
}

輸出結果

我是Task沒有返回參數
2

一次性建立多個任務場景

static void test1()
{
  Task[] taskArray = new Task[10];
  for (int i = 0; i < 10; i++)
  {
    int bb = i;
    Task t = Task.Run(() => { Console.WriteLine("任務ID:{0}, 結果:{1}",Thread.CurrentThread.ManagedThreadId, bb); });
    taskArray[i] = t;
  }
  // 等待所有任務完成
  Task.WaitAll(taskArray);
}

輸出結果

任務ID:4, 結果:0
任務ID:10, 結果:4
任務ID:7, 結果:1
任務ID:8, 結果:2
任務ID:10, 結果:7
任務ID:11, 結果:5
任務ID:9, 結果:3
任務ID:12, 結果:6
任務ID:7, 結果:8
任務ID:8, 結果:9

Task阻塞的三種方式

  • Wait(): 等待單個線程任務完成
  • WaitAll():來指定等待的一個或多個線程結束
  • WaitAny():來指定等待任意一個線程任務結束
static void test3()
{
  // 方式一: wait方法
  Task t = Task.Run(() => { Console.WriteLine("方式1:任務1......"); }) ;
  // 等待 上述任務完成
  t.Wait();
  Console.WriteLine("方式一結束..........");


  // 方式二: waitAll 方法
  Task tt = Task.Run(() => { Console.WriteLine("方式2:任務1......"); });
  Task tt2 = Task.Run(() => { Console.WriteLine("方式2:任務2......"); });
  Task.WaitAll(tt,tt2);
  Console.WriteLine("方式二結束..........");


  // 方式三:waitAny 方法
  Task ttt = Task.Run(() => { Console.WriteLine("方式3:任務1......"); });
  Task ttt2 = Task.Run(() => { Console.WriteLine("方式3:任務2......"); });
  Task.WaitAny(ttt, ttt2);
  Console.WriteLine("方式三結束..........");


}

輸出結果

方式1:任務1......
方式一結束..........
方式2:任務1......
方式2:任務2......
方式二結束..........
方式3:任務2......
方式3:任務1......
方式三結束..........

Task任務的延續(xù)

  • WhenAll().ContinueWith() : 作用是當 WhenAll() 中指定的線程任務完成后再執(zhí)行 ContinueWith() 中的任務,也就是線程任務的延續(xù)。而由于這個等待是異步的,因此不會給主線程造成阻塞
  • WhenAll(task1,task2,...): Task的靜態(tài)方法,作用是異步等待指定任務完成后,返回結果。當線程任務有返回值時,返回Task對象,否則返回Task對象。
  • WhenAny() :用法與WhenAll()是一樣的,不同的是只要指定的任意一個線程任務完成則立即返回結果。
  • ContinueWith(): Task類的實例方法,異步創(chuàng)建當另一任務完成時可以執(zhí)行的延續(xù)任務。也就是當調用對象的線程任務完成后,執(zhí)行ContinueWith()中的任務
static void test4()
{
  Task t = Task.Run(() => { Thread.Sleep(1000); Console.WriteLine("我是線程任務....."); });
  // 異步創(chuàng)建延續(xù)任務
  Task.WhenAll(t).ContinueWith((data) => { Console.WriteLine("我是延續(xù)任務...."); });


  Console.WriteLine("這是主線程........");
  Console.ReadKey();


}

輸出結果

這是主線程........
我是線程任務.....
我是延續(xù)任務....

注:Task任務的延續(xù) 與 上面阻塞相比,主要的好處就是 延續(xù)是異步的不會阻塞主線程

Task的父子任務

  • TaskCreationOptions.AttachedToParent: 用于將子任務依附到父任務中
static void test5()
{
  // 建立一個父任務
  Task parentTask = new Task(() => {
    // 創(chuàng)建兩個子任務,依附在父任務上
    Task.Factory.StartNew(() => { Console.WriteLine("子task1任務。。。。。。"); }, TaskCreationOptions.AttachedToParent);
    Task.Factory.StartNew(() => { Console.WriteLine("子task2任務。。。。。。"); }, TaskCreationOptions.AttachedToParent);
    Thread.Sleep(1000);
    Console.WriteLine("我是父任務........");
  });
  parentTask.Start();
  parentTask.Wait();
  Console.WriteLine("這里是主線程.......");
  Console.ReadKey();
}

輸出結果

子task2任務。。。。。。
子task1任務。。。。。。
我是父任務........
這里是主線程.......

**Task中的任務取消 **

Task中的取消功能使用的是CanclelationTokenSource,即取消令牌源對象,可用于解決多線程任務中協作取消和超時取消

  • CancellationToken Token: CanclelationTokenSource類的屬性成員,返回CancellationToken對象,可以在開啟或創(chuàng)建線程時作為參數傳入。
  • IsCancellationRequested: 表示當前任務是否已經請求取消。Token類中也有此屬性成員,兩者互相關聯。
  • Cancel(): CanclelationTokenSource類的實例方法,取消線程任務,同時將自身以及關聯的Token對象中的IsCancellationRequested屬性置為true。
  • CancelAfter(int millisecondsDelay) :CanclelationTokenSource類的實例方法,用于延遲取消線程任務。

取消任務的兩種情況

  • 情況一: 通過Cancel()方法
  • 情況二: 通過CancelAfter(milliseconds) 方法
static void test6()
{
  // 情況一: 直接取消
  // 創(chuàng)建取消令牌源對象
  CancellationTokenSource cst = new CancellationTokenSource();
  //第二個參數傳入取消令牌
  Task t = Task.Run(() => {
    while (!cst.IsCancellationRequested)
    {
      Thread.Sleep(500);
      Console.WriteLine("情況一,沒有接收到取消信號......");
    }
  }, cst.Token);


  Thread.Sleep(1000);
  //1秒后結束
  cst.Cancel(); 
  Console.ReadKey();




  // 情況二: 延遲取消
  CancellationTokenSource cst2 = new CancellationTokenSource();
  Task t2 = Task.Run(() => {
    while (!cst2.IsCancellationRequested)
    {
      Console.WriteLine("情況二,沒有接收到取消信號......");
    }
  }, cst2.Token);
  //1秒后結束
  cst2.CancelAfter(1000);
  Console.ReadKey();
}

**Task跨線程訪問界面控件 **

通過 TaskScheduler.FromCurrentSynchronizationContext() 獲取TaskScheduler,并將其放入Task的start() 方法中 或 放入延續(xù)方法中即可

  • 放入start() 方法中
  • 放入 ContinueWith() 延續(xù)方法中
// 通過start方法
private void button1_Click(object sender, EventArgs e)
{
    Task t = new Task(() =>
    {
        // 為界面控件賦值
    this.textBox1.Text = "線程內賦值";
    });

    task.Start(TaskScheduler.FromCurrentSynchronizationContext());
}




// 通過延續(xù)方法
private void button1_Click(object sender, EventArgs e)
{
    Task.Run(() =>
    {
      Thread.Sleep(1000);
    }).ContinueWith(t => {
      this.textBox1.Text = "線程內賦值";
    }, TaskScheduler.FromCurrentSynchronizationContext());
}

Task的異常處理

異常捕獲

  • Task線程的異常處理 不能直接將線程對象相關代碼try-catch來捕獲 ,需要通過調用線程對象的wait()函數來進行線程的異常捕獲
  • 線程的異常會聚合到AggregateException異常對象中(AggregateException是專門用來收集線程異常的異常類),多個異常 需要通過遍歷該異常對象來獲取異常信息
  • 如果捕獲到線程異常之后,還想繼續(xù)往上拋出,就需要調用AggregateException對象的Handle函數,并返回false。(Handle函數遍歷了一下AggregateException對象中的異常)
static void test7()
{
  Task t = Task.Run(() =>
  {
    throw new Exception("異常拋出.....");
  });


  try
  {
    t.Wait();
  }
  catch (AggregateException ex)
  {
    Console.Error.WriteLine(ex.Message);


    foreach (var item in ex.InnerExceptions)
    {
      Console.WriteLine("內異常:"+item.Message);
    }
    //將異常往外拋出
    // ex.Handle(p => false);
  }
  Console.ReadKey();
}

輸出結果

One or more errors occurred. (異常拋出.....)
內異常:異常拋出.....
聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規(guī)問題,請聯系本站處理。 舉報投訴
  • 微軟
    +關注

    關注

    4

    文章

    6651

    瀏覽量

    105244
  • 線程
    +關注

    關注

    0

    文章

    507

    瀏覽量

    20021
  • Thread
    +關注

    關注

    2

    文章

    85

    瀏覽量

    26289
收藏 人收藏

    評論

    相關推薦

    鴻蒙內核源碼Task/線程技術分析

    前言 在鴻蒙內核中,廣義上可理解為一個Task就是一個線程 一、怎么理解Task 1. 官方文檔是怎么描述線程 基本概念 從系統的角度看,線程是競爭系統資源的最小運行單元。線程可以使用或等待CPU
    的頭像 發(fā)表于 10-18 10:42 ?2411次閱讀
    鴻蒙內核源碼<b class='flag-5'>Task</b>/線程技術分析

    高速接口MIPI DPHY配置task函數

    景芯SoC訓練營有同學問Verdi如何加載task函數里面的波形,這里以高速圖像接口MIPI為例,給大家介紹下吧。
    的頭像 發(fā)表于 11-18 16:59 ?1117次閱讀
    高速接口MIPI DPHY配置<b class='flag-5'>task</b>函數

    RAW task

    這篇文檔會主要選擇些API講解,讀者可以對著代碼仔細理解。1 RAW_U16 raw_task_create(RAW_TASK_OBJ*task_obj, RAW_U8*task
    發(fā)表于 02-27 14:00

    task問題

    背景如下:小弟想用一個task實現16個時鐘周期的延遲,然后產生一標志位cnt_key用作后面語句的激勵,但用modlesim仿真的時候cnt_key沒有起到激勵作用,程序如下,請各路大神幫忙指點下
    發(fā)表于 06-12 10:11

    AWR1642開發(fā),使用Task_create創(chuàng)建了多個task,請問task都沒有運行是怎么回事?

    AWR1642開發(fā),使用Task_create創(chuàng)建了多個task,task都沒有運行是怎么回事。在main中創(chuàng)建了task,還需要在哪里初始化嗎?
    發(fā)表于 08-08 08:29

    【HarmonyOS】Task/線程管理篇

    原文鏈接:https://my.oschina.net/u/3751245/blog/4595539本文分析Task/線程管理源碼 詳見:los_task.c目錄前言一、怎么理解Task1. 官方
    發(fā)表于 10-19 14:54

    簡談FPGA verilog中的task用法

    ????????大家好,又到了每日學習的時間了,今天我們來聊一聊FPGA verilog中的task用法。 ? ? ? ?任務就是一段封裝在“task-endtask”之間的程序。任務是通過調用
    的頭像 發(fā)表于 08-09 18:59 ?4.1w次閱讀

    如何進行Android中Task任務棧的分配

    這意思就是說Task實際上是一個Activity棧,通常用戶感受的一個Application就是一個Task。從這個定義來看,Task跟Service或者其他Components是沒有任何聯系的,它
    發(fā)表于 07-03 17:42 ?0次下載
    如何進行Android中<b class='flag-5'>Task</b>任務棧的分配

    帶你了解 TensorFlow Lite Task Library模型接口

    額外的代碼來處理復雜的邏輯,如數據轉換、預處理/后處理、加載關聯文件等。 額外的代碼 今天,我們將為大家介紹 TensorFlow Lite Task Library,這是一組功能強大且易于使用的模型
    的頭像 發(fā)表于 09-30 10:26 ?2483次閱讀

    RTA OS系列介紹01-Task

    AUTOSAR OS主要包含Task, ISRs, Events, Resources, Application, Counter, Alarms, Schedule Table等OS對象。后續(xù)將對如上提到的八個對象進行分別介紹,本篇介紹的內容為Task,下面進入正題:
    的頭像 發(fā)表于 12-21 14:13 ?2549次閱讀

    verilog中的task用法

    任務就是一段封裝在“task-endtask”之間的程序。任務是通過調用來執(zhí)行的,而且只有在調用時才執(zhí)行,如果定義了任務,但是在整個過程中都沒有調用它,那么這個任務是不會執(zhí)行的。調用某個任務時可能
    的頭像 發(fā)表于 03-23 15:13 ?1481次閱讀

    Verdi查看task內部變量

    任務(task)可以用來描述共同的代碼段,并在模塊內任意位置被調用,讓代碼更加的直觀易讀。task 更像一個過程,過程內一般按順序執(zhí)行,完成各種邏輯控制。
    的頭像 發(fā)表于 03-26 16:08 ?6477次閱讀
    Verdi查看<b class='flag-5'>task</b>內部變量

    verilog中的task用法介紹

    任務就是一段封裝在“task-endtask”之間的程序。任務是通過調用來執(zhí)行的,而且只有在調用時才執(zhí)行
    的頭像 發(fā)表于 06-05 16:21 ?1968次閱讀

    verilog中function和task的區(qū)別

    在Verilog中,Function和Task是用于模塊化設計和重用代碼的兩種重要元素。它們允許開發(fā)人員將復雜的操作分解為更小的功能單元,并在需要時調用它們。雖然Function和Task在某些方面
    的頭像 發(fā)表于 02-22 15:40 ?2317次閱讀

    verilog task和function區(qū)別

    verilog中的task和function都是用于實現模塊中的可重復的功能,并且可以接收參數和返回結果。但是它們在編寫和使用上有一些區(qū)別。下面將詳細介紹task和function的區(qū)別。 語法結構
    的頭像 發(fā)表于 02-22 15:53 ?1430次閱讀