首页 > 编程语言 >C#多线程编程的Task(任务全面解析)

C#多线程编程的Task(任务全面解析)

时间:2024-02-05 17:55:17浏览次数:30  
标签:Task Console Thread C# task 线程 WriteLine 多线程

原文链接:https://www.cnblogs.com/xietianjiao/p/7429742.html

Task是.NET4.0加入的,跟线程池ThreadPool的功能类似,用Task开启新任务时,会从线程池中调用线程,而Thread每次实例化都会创建一个新的线程。

 我们可以说Task是一种基于任务的编程模型。它与thread的主要区别是,它更加方便对线程进程调度和获取线程的执行结果。

 

Task类和Task<TResult>类
前者接收的是Action委托类型
后者接收的是Func<TResult>委托类型

 

任务和线程的区别:

1、任务是架构在线程之上的,也就是说任务最终还是要抛给线程去执行。

2、任务跟线程不是一对一的关系,比如开10个任务并不是说会开10个线程,这一点任务有点类似线程池,但是任务相比
线程池有很小的开销和精确的控制。

一、Task的创建

1、直接创建

var task1 = new Task(() =>
{
         Console.WriteLine("Begin");
         System.Threading.Thread.Sleep(5000);
         Console.WriteLine("Finish");
   });
Console.WriteLine("Before start:" + task1.Status);
task1.Start();

  2、工厂创建

Task.Factory.StartNew(()={

});

  3、4.5以后Run运行

Task.Run(()=>{

});

  4、一种方便获取返回值的方式

static void Main(string[] args) 
        { 
            var tcs = new TaskCompletionSource<int>(); 
            new Thread(() => { 
                Thread.Sleep(5000); 
                int i = Enumerable.Range(1, 100).Sum(); 
                tcs.SetResult(i); }).Start();//线程把运行计算结果,设为tcs的Result。 
              Task<int> task = tcs.Task; 
              Console.WriteLine(task.Result); //此处会阻塞,直到匿名线程调用tcs.SetResult(i)完毕 
        }

  

二、细节解释

看下面代码:

namespace WpfApplication6
{
    /// <summary>
    /// MainWindow.xaml 的交互逻辑
    /// </summary>
    public partial class MainWindow : Window
    {
 
        public MainWindow()
        {
            InitializeComponent();
            ConsoleManager.Show();//打开控制台窗口 
        }
 
        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            Console.WriteLine("主线程启动");
            Task task = Task.Run(() => {
                Thread.Sleep(1500);
                Console.WriteLine("task启动");
            });
            Thread.Sleep(300);
            task.Wait();
            Console.WriteLine("主线程结束");
        }
 
    }
}

  结果:

 

分析:

开启新任务的方法:Task.Run()或者Task.Factory.StartNew(),开启的是后台线程

要在主线程中等待后台线程执行完毕,可以使用Wait方法(会以同步的方式来执行)。不用Wait则会以异步的方式来执行。

thread和Task的区别,thread new多少个就会创建多少个线程,而task是利用线程池中的线程。

 

task<TResult>就是有返回值的Task,TResult就是返回值类型。示例:

private void Window_Loaded(object sender, RoutedEventArgs e)
{
    Console.WriteLine("主线程开始");
    //返回值类型为string
    Task<string> task = Task<string>.Run(() => {
        Thread.Sleep(2000);
        return Thread.CurrentThread.ManagedThreadId.ToString();
    });
    //会等到task执行完毕才会输出;
    Console.WriteLine(task.Result);
    Console.WriteLine("主线程结束");
}

  

通过task.Result可以取到返回值,若取值的时候,后台线程还没执行完,则会等待其执行完毕!

简单提一下:

Task任务可以通过CancellationTokenSource类来取消。

三、Task的其他方法

Task.Wait();    //阻塞当前线程
Task.WaitAll(); //阻塞当前线程直到所有的任务执行完毕
Task.WaitAny(); //阻塞当前线程直到有任意一个任务执行完毕


Task.ContinueWith(
task=>{

});              //执行完上一个任务后继续执行,并将上一个任务(包括结果)传递给下一个代码块


一种是使用GetAwaiter方法。GetAwaiter方法返回一个TaskAwaiter结构,该结构有一个OnCompleted事件,只需对

OnCompleted事件赋值,即可在完成后调用该事件。 

static void Main(string[] args) 
        { 
            Task<int> Task1 = Task.Run<int>(() => { return Enumerable.Range(1, 100).Sum(); }); 
            var awaiter = Task1.GetAwaiter(); 
            awaiter.OnCompleted(() => 
            { 
                Console.WriteLine("Task1 finished"); 
                int result = awaiter.GetResult(); 
                Console.WriteLine(result); // Writes result 
            }); 
            Thread.Sleep(1000); 
        }

  四、任务的中断

var tokenSource = new CancellationTokenSource();
            var token = tokenSource.Token;
            var task = Task.Factory.StartNew(() =>
            {
                for (var i = 0; i < 1000; i++)
                {
                    System.Threading.Thread.Sleep(1000);
                    if (token.IsCancellationRequested)
                    {
                        Console.WriteLine("Abort mission success!");
                        return;
                    }
                }
            }, token);

            //注册cancel后要执行的代码
            token.Register(() =>
            {
                Console.WriteLine("Canceled");
            });
            Console.WriteLine("Press enter to cancel task...");
            Console.ReadKey();
            //调用取消
            tokenSource.Cancel();

  五、任务的中断取消

var tokenSource = new CancellationTokenSource();
            var token = tokenSource.Token;
            var task = Task.Factory.StartNew(() =>
            {
                for (var i = 0; i < 1000; i++)
                {
                    System.Threading.Thread.Sleep(1000);
                    if (token.IsCancellationRequested)
                    {
                        Console.WriteLine("Abort mission success!");
                        return;
                    }
                }
            }, token);

            //注册cancel后要执行的代码
            token.Register(() =>
            {
                Console.WriteLine("Canceled");
            });
            Console.WriteLine("Press enter to cancel task...");
            Console.ReadKey();
            //调用取消
            tokenSource.Cancel();

  六、异常处理

异常处理;
对于某些匿名的Task(通过 Task.Run方法生成的,不调用wait,也不关心是否运行完成),某些情况下,记录它们的异

常错误也是有必要的。这些异常称作未观察到的异常(unobserved exceptions)。可以通过订阅一个全局的静态事件

TaskScheduler.UnobservedTaskException来处理这些异常。只要当一个Task有异常,并且在被垃圾回收的时候,才会触

发这一个事件。如果Task还处于被引用状态,或者只要GC不回收这个Task,这个UnobservedTaskException事件就不会被

触发
GC.Collect();
GC.WaitForPendingFinalizers();

  

七、Task的状态


Created:表示默认初始化任务,但是“工厂创建的”实例直接跳过。

WaitingToRun: 这种状态表示等待任务调度器分配线程给任务执行。

RanToCompletion:任务执行完毕。

标签:Task,Console,Thread,C#,task,线程,WriteLine,多线程
From: https://www.cnblogs.com/Dongmy/p/18008575

相关文章

  • docker 启动jar包
    1、编写Dockerfile文件FROMopenjdk:8ENVTZ="Asia/Shanghai"ADDcim-gisportal.jarcim-gisportal.jarADDnohup.outnohup.outENTRYPOINT["nohup","java","-jar","/cim-gisportal.jar",">nohup.out&&quo......
  • Cucumber步骤中传Data Table作为参数
    引用链接:http://cukes.info/step-definitions.htmlDataTablesDataTablesarehandyforspecifyingalargerpieceofdata:Giventhefollowingusersexist:|name|email|phone||Aslak|[email protected]|123||Matt|[email protected]|2......
  • Cesium常用知识点
    构建四元数//地理位置坐标(三维)constposition=Cesium.Cartesian3.fromDegrees(-123.0744619,44.0503706,height);constheading=Cesium.Math.toRadians(135);//航向constpitch=0;//俯仰constroll=0;//横滚角consthpr=newCesium.Headi......
  • 【板子】网络流(Dinic)
    #include<bits/stdc++.h>usingnamespacestd;constintN=205;constintM=205;constintINF=0x3f3f3f3f;intedgeid=2;inthead[N];structedge{intv,w,nxt;}e[M*2];inlinevoidaddedge(intu,intv,intw){e[edgeid].v=v;e[ed......
  • C#之lock
    原文链接:https://blog.csdn.net/u012563853/article/details/124767902lock语法是:privateobjecto=newobject();//创建一个对象publicvoidWork(){lock(o)//锁住这个对象{//做一些必须按照顺序做的事情}}目的是,在多线程中,使用lock后,能......
  • c++的类开发第一篇
    class_1什么是接口?类就是一种公共接口,公众(public)是使用类的程序,交互系统由类对象组成,而接口由编写类的人提供的方法组成。接口让程序员能够编写与类对象交互的代码,从而让程序能够使用类对象。例如,要计算string对象中包含多少个字符,您无需打开对象,而只需使用string类提供的s......
  • Proxmox 7.4 使用vgpu_unlock,为GTX1060开启vGPU支持
    本文在2021年发布的博客《Proxmox5.4使用vgpu_unlock,为GTX1060开启vGPU支持》,介绍了ProxmoxVE5.4上部署vGPUunlock的操作步骤。 后续有发布了在 ProxmoxVE7.x上支持vGPU的博客《Proxmox7.2部署DoraCloud桌面云,支持vGPU》,实现了通过3个脚本完成vGPU的配置。 ......
  • MCAL-MCU
    1.概述https://blog.csdn.net/qq_43629659/article/details/133050046 MCU模块提供了访问内核相关功能的API,如时钟配置、初始化RAM、设置低功耗模式、提供复位接口等等。1.1时钟上图左边位输入时钟源,右侧为输出时钟,需要选择合适的时钟源并通过倍频,分频来得到需要的时钟源。......
  • pytorch数据集MNIST训练与测试实例
      importosimporttorchimportnumpyasnpfromtorch.utils.dataimportDataLoaderfromtorchvision.datasetsimportMNISTfromtorchvision.transformsimportCompose,ToTensor,Normalizefromtorch.optimimportAdamimporttorch.nnasnnimporttorch.nn.......
  • MFC 自定义消息
    ▲Demo示例新建基于对话框的Demo程序。头文件://自定义数据类型,用来测试消息数据传递typedefstructtagStudent{CStringName;intAge;}Student_t;//Dlgheaderpublic:afx_msgvoidOnBnClickedButtonCustomMsg();afx_msgLRESULTOnCusto......