Task用法详解

本文详细介绍了C#中Task的创建与运行,包括使用new、Task.Factory.StartNew和Task.Run的方式。还探讨了具有返回值的任务,以及阻塞线程的方法如Wait、WaitAll和WaitAny。此外,讲解了Task的延时操作,如WhenAll和WhenAny用于在任务完成后执行后续操作。最后,讨论了如何取消Task的执行,并展示了通过Action实现异步编程的例子。
摘要由CSDN通过智能技术生成

一. 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);
        } 
    });
}

 

  • 3
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值