Task用法详解-程序员宅基地

技术标签: c#  task  多线程  

一. Task的创建和运行,Task有如下三种方法创建

//Task的创建与运行
static void Main(string[] args)
{
    //1.new 方式实例化一个Task,需要通过Start方法启动
    Task task=new Task(()=>
    {
        Thread.Sleep(1000);
        Console.WriteLine($"hello,task1的线程ID为:{0}",Thread.CurrentThread.ManagedThreadId);            
    });
    task.Start();
    //2.Task.Factory.StartNew(Action)创建和启动一个Task
    Task task2=Task.Factory.StartNew(()=>
    {
        Thread.Sleep(1000);
        Console.WriteLine($"hello,task2的线程ID为:{0}",Thread.CurrentThread.ManagedThreadId);
    });
    //3.Task.Run(Action action)将任务放到线程池队列中,返回并启动一个Task
    Task task3=Task.Run(()=>
    {
       Thread.Sleep(1000);
       Console.WriteLine($"hello,task3的线程ID为:{0}",Thread.CurrentThread.ManagedThreadId);
    });
    Console.WriteLine("执行主线程");
    Console.ReadKey();
}

运行结果:

二.创建具有返回值的Task

如果使用Task.Result获取结果时会阻塞线程,即如果task没有完成,会等到task执行完成之后再执行后面的代码

static void Main(string[] args)
{
    //1.使用New方法实例化一个Task,需要通过Start方法启动
    Task<string> task1=new Task<string>(()=>
    {
       return $"hello,task1的id为{Thread.CurrentThread.ManagedThreadId}"; 
    });
    task1.Start();
    //2.使用Task.Factory.StartNew()创建和启动一个Task
    Task<string> task2=Task.Factory.StartNew<string>(()=>
    {
       return $"Hello,task2的id为{Thread.CurrentThread.ManagedThreadId}"; 
    });
    //3.Task.Run(Func func)将任务放在线程池队列,返回并启动一个Task
    Task<string> task3=Task.Run<string>(()=>
    {
        return $"hello,task3的id为{Thread.CurrentThread.ManagedThreadId}";
    });
    Console.WriteLine("执行主线程");
    Console.WriteLine(task1.Result);
    Console.WriteLine(task2.Result);
    Console.ReadKey();
}

运行结果:

如果阻塞线程,则需要RunSynchronously()来阻塞线程

static void Main(string[] args)
{
    Task task=>new Task(()=>
    {
        Thread.Sleep(1000);
        Console.WriteLine("执行Task结束");
    });
    //同步执行,task会阻塞线程
    task.RunSynchronously();
    Console.WriteLine("执行主线程结束");
    Console.ReadKey();
}

运行结果:

三.Task的阻塞的方法

Wait:表示等待task执行完成,类似于Join()

 WaitAll:当存在多个Task,只有所有的Task执行完成之后再解除阻塞

WaitAny:当存在多个Task,只要完成一个Task就解除阻塞

static void Main(string[] args)
{
    Task task1=new Task(()=>
    {
        Thread.Sleep(500);
        Console.WriteLine("线程1执行完成");
    });
    task1.Start();
    Task task2=new Task(()=>
    {
        Thread.Sleep(1000);
        Console.WriteLine("线程2执行完成");
    });
    task2.Start();
    //阻塞线程。task1,task2都执行完毕再执行主线程
    Task.WaitAll(new Task[]{task1,task2});
    Console.WriteLine("主线程执行完毕!");
    Console.ReadKey();
}

运行结果:

四:Task的延时操作

Wait/WaitAny/WaitAll的返回值为void,实现单纯阻塞线程.如果需要在执行完成之后再执行一些特定的代码则需要使用WhenAll/WhenAny。

task.WhenAll(Task[] tasks).ContinueWith:表示所有的task都执行完成之后再执行后续操作

task.WhenAny(Task[] tasks).ContinueWith:表示任意一个task执行完毕之后再执行后续操作

static void Main(string[] args)
{
    Task task1=new Task(()=>
    {
        Thread.Sleep(500);
        Console.WriteLine("task1执行完毕!");
    });
    task1.Start();

    Task task2=new Task(()=>
    {
        Thread.Sleep(1000);
        Console.WriteLine("task2执行完毕!");
    });
    task2.Start();

    //task1与task2执行完成之后执行ContinueWith的后续操作
    Task.WhenAll(task1,task2).ContinueWith((t)=>
    {
        Thread.Sleep(1000);
        Console.WriteLine("执行后续的操作");
    });
    Console.WriteLine("主程序执行完毕!");
    Console.ReadKey();    
}
//下面这段代码的执行和上面是一样的,使用Task.Factory.ContinueWhenAll/ContinueWhenAny实现
static void Main(string[]  args)
{
    Task task1=new Task(()=>
    {
        Thread.Sleep(500);
        Console.WriteLine("线程1执行完毕!");
    });
    task1.Start();
    
    Task task2=new Task(()=>
    {
        Thread.Sleep(1000);
        Console.WriteLine("线程2执行完毕!");
    });
    task2.Start();

    //通过Task.Factory实现
    Task.Factory.ContinueWhenAll(new Task[]{task1,task2},(t)=>
    {
        Thread.Sleep(1000);
        Console.WriteLine("执行后续操作");
    });
    
    Console.WriteLine("主线程执行完毕!");
    Console.ReadKey();
}

五:Task取消执行:CancelTokenSource,

       Task不能像Thread一样粗暴的终止掉线程,abort();然后线程置为null;但是在实际开发中是有可能粗暴的终止线程的这时候只能使用Thread替换

static void Main(string[] args)
{
    CancellationTokenSource source=new CancellationTokenSource();
    int idx=0;
    //开启一个task执行任务
    Task task1=new Task(()=>
    {
        while(!source.IsCancellationRequested)
        {
            Thread.Sleep(1000);
            Console.WriteLine($"第{++idx}次执行,线程执行中");
        }
    });
    task1.Start();
    //5秒后取消任务执行
    //Thread.Sleep(5000);
    //source.Cancel();
    //也可以通过source.Token.Register(Action action)注册去取消任务触发毁掉函数
    source.CancelAfter(10000);
    Console.ReadKey();
}

运行结果:

六:通过Action实现异步的编程

private void btn_Click(object sender,EventArgs e)
{
    Task.Run(()=>
    {
        Action<int> setValue=(i)=>{txt1.Text=i.ToString();};
        for(int i=0;i<100000;i++)
        {
            txt1.Text.Invoke(setValue,i);
        } 
    });
}

 

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/cdc8596/article/details/112005117

智能推荐

没有第三方控件用RadioGroup做轮播图--MainActivity 主页面和布局_mainactivity类怎么转成radiogroup类-程序员宅基地

文章浏览阅读405次。没有第三方控件用RadioGroup做轮播图--MainActivity 主页面和布局_mainactivity类怎么转成radiogroup类

Spark闭包与序列化_闭包序列化-程序员宅基地

文章浏览阅读1.9w次,点赞9次,收藏22次。本文原文出处: http://blog.csdn.net/bluishglc/article/details/50945032 严禁任何形式的转载,否则将委托CSDN官方维护权益!在Spark的官方文档再三强调那些将要作用到RDD上的操作,都会被分发到各个worker节点上去执行,我们都知道,这些操作实际上就是一些函数和涉及的变量组成的闭包,这里显然涉及到一个容易被忽视的问题:闭包的“序列化”。显然_闭包序列化

Unity ECS Manual [17]_unity ecs1.0-程序员宅基地

文章浏览阅读123次。Job dependencies  Unity根据系统读取和写入的ECS组件来分析每个系统的数据依赖性。如果一个在框架中较早更新的系统读取了后来的系统所写的数据,或者写了后来的系统所读的数据,那么第二个系统就会依赖第一个系统。为了防止竞争条件,作业调度器在运行一个系统的作业之前,要确保该系统所依赖的所有作业已经完成。  一个系统的Dependency属性是一个JobHandle,代表了该系统的ECS相关依赖关系。在OnUpdate()之前,Dependency属性反映了系统对先前作业的传入依赖关系。默认_unity ecs1.0

【干货合集】看完这16篇文章,不再做敏捷项目管理上的小白!_项目管理干货 site:csdn.net-程序员宅基地

文章浏览阅读1.1k次。原文链接:点击打开链接摘要: 流行技术大狂欢,5月29日即将召开的第二届研发效能嘉年华,带来了前沿技术理念及实践技术成果分享。本次峰会将有10位技术大咖进行干货分享,多角度,不同领域的带领大家了解高效研发。项目管理的主流模式有哪几种?传统项目管理通常采用的是瀑布式、部分迭代开发模式,要求在项目建设时,需求足够明确、文档足够规范,迭代过程中需求变更越多、越晚,对项目影响越大,会影响到项目的交付质量。..._项目管理干货 site:csdn.net

大数据(二十七):Sqoop常用命令和公用参数_大数据 公参-程序员宅基地

文章浏览阅读211次。一、常用命令列举 命令 类 说明 import ImportTool 将数据导入到集群 export ExportTool 将集群数据导出 codegen CodeGenTool ..._大数据 公参

基于MAC地址的安全配置与管理实战_如何防范mac地址泛滥-程序员宅基地

文章浏览阅读1.9k次,点赞2次,收藏10次。MAC地址是网络设备中不变的物理地址,基于MAC地址的接入控制成了最直接,甚至可能是大多数情况下最有效的控制手段。在二层交换网络中,是通过依靠保存在交换机中的MAC地址表来进行寻址的,这时如果控制交换机中存储的MAC地址表就可以控制一些非法设备的接入,让其他设备不能与他进行通信。在华为S系列交换机中,为了实现这个目的提供了多种基于MAC地址的安全手段,如限制接口学习MAC地址表项的数量,限制交..._如何防范mac地址泛滥

随便推点

cookie和session机制之间的区别与联系-程序员宅基地

文章浏览阅读1.1w次。具体来说cookie机制采用的是在客户端保持状态的方案。它是在用户端的会话状态的存贮机制,他需要用户打开客户端的cookie支持。cookie的作用就是为了解决HTTP协议无状态的缺陷所作的努力.而session机制采用的是一种在客户端与服务器之间保持状态的解决方案。同时我们也看到,由于采用服务器端保持状态的方案在客户端也需要保存一个标识,所以session机制可能需要借助于cookie机制来达到

微信小程序初识---地图开发_微信公小程序地图开发-程序员宅基地

文章浏览阅读2k次。微信小程序似乎比较火,很多公司除了自家app外都要给自家再弄个小程序,于是乎空余时间就试了试小程序,现记录下地图页面的开发。小程序官方文档也比较全,基本上面的东西都有,有前端开发经验的上手更简单。先上图 : 1.层级结构: 小程序类似于app,以页面为单位,每个页面包含4个文件: .js .json .wxml .wxss 为后缀的文件,官方文_微信公小程序地图开发

Anaconda详细安装及使用教程(带图文)-程序员宅基地

文章浏览阅读10w+次,点赞1.4k次,收藏7.9k次。Anacond的介绍Anaconda指的是一个开源的Python发行版本,其包含了conda、Python等180多个科学包及其依赖项。因为包含了大量的科学包,Anaconda的下载文件比较大(约531 MB),如果只需要某些包,或者需要节省带宽或存储空间,也可以使用Miniconda这个较小的发行版(仅包含conda和Python)。Conda是一个开源的包、环境管理器,可以用于..._anaconda

JDK的动态代理(附带完整代码demo)_jdk动态代理demo-程序员宅基地

文章浏览阅读1.5k次。JDK的代理,实际上是对Java接口(Interface)的代理,而且只能对接口进行代理,达到的效果是,当调用指定接口的指定方法时,会执行特定的操作。例如,HelloService是一个接口,public String sayHello(String msg)是该接口的其中一个方法,当代码调用该接口的sayHello方法时,会执行规定好的动作。这里会有一个问题,HelloService接口的实现类是从哪里来的呢?这里HelloService接口的实现类是由代理动态生成的实现类。所以想为一个接口生成代理,需要_jdk动态代理demo

设计模式—组合与聚合详解_聚合是菱形空心吗-程序员宅基地

文章浏览阅读2.2k次。在UML类图中,聚合是空心菱形,组合是实心菱形。简单来说:组合的关系就像一个学生和他的各个器官,手、脚、鼻子、眼睛等器官组合成了一个学生,这些器官离开了学生这个个体,也就失去了意义,无法单独生存,因此,组合关系的类具有相同的生命周期,它们的联系更加紧密。而聚合就像一个班级有许多学生构成,学生离开了班级,作为一个个体仍然能够存活。聚合案例public ClassRoom{ public..._聚合是菱形空心吗

【备战金三银四】2022史上最全Android 面试题_2022 最全android面试题合集-程序员宅基地

文章浏览阅读499次。小编经历过这么多年的摸爬滚打,面试过也被面试过。现总结与归纳Android开发相关面试题:初级面试题:1、Activity启动模式有哪些,分别有什么不同?2、Service启动模式有哪些,对应的生命周期?IntentService呢?3、ContentProvider的作用,是否支持多线程和多进程4、Broadcast的注册方式,对应的生命周期是什么,有序和无序那种可以中断广播?5、AsyncTask的作用,如何使用(包括有哪些方法,能说出同步异步,能说出不同Android版本下的区别加分)6_2022 最全android面试题合集