C# Task类- 多线程学习2

上一篇文章(C# Thread类 - 多线程学习1)说过多线程之Thread 类,下面继续学习多线程的另一个更重要的知识点:Task 类,如果有时间也建议看下上面的这篇文章,或许有用呐。

Thread线程是用来创建并发的一种低级别工具,它具有一些限制,尤其是:

  • 虽然开始线程的时候可以方便的传入数据,但是当join的时候很难从线程获得返回值。
  • 可能需要设置一些共享字段。
  • 如果操作抛出异常,铺货和传播该异常都很麻烦
  • 无法告诉线程在结束时开始另外的工作,你必须进行join操作(在进程中阻塞当前的线程)
  • 很难使用较小的并发(concurrent)来组件大型的并发

Task类可以很好的解决上述问题,它是一个高级抽象:它代表了一个并发操作(concurrent),该操作可能有Thread支持,或不由Thread支持。

  • Task是可组合的(可使用continuation把他们穿成链)。
  • Tasks可以使用线程池来减少启动延迟。
  • 使用TaskCompletionSource,Tasks可以利用回调的方式,在等待I/O绑定操作时完全避免使用线程。

Task建立多线程有多种方法,下面通过代码进行说明。代码可能有点长,但是把它分块就比较好理解的,因为是多种方法合并在一起进行介绍的,所以整个代码与输出结果比较长。

直接上代码,后面有对代码的解析:

using System;
using System.Threading; 
using System.Threading.Tasks;

namespace ch_Task
{
    class Program
    {
        static void CallTask2(string name)
        {
            Console.WriteLine($"taskID:{Task.CurrentId} beginning! ---name:" + name);
            for (int i = 1; i <= 5; i++)
            {
                Thread.Sleep(500);
                Console.WriteLine($"{i.ToString()} ---name:task2");
            }
            Console.WriteLine($"taskID:{Task.CurrentId} finished! ---name:" + name);
        }
        public static void CallTask3()
        {
            Console.WriteLine($"taskID:{Task.CurrentId} beginning! ---name:task3");
            for (int i = 1; i <= 5; i++)
            {
                Thread.Sleep(500);
                Console.WriteLine($"{i.ToString()} ---name:task3");
            }
            Console.WriteLine($"taskID:{Task.CurrentId} finished! ---name:task3");
        }
        public static void CallTask3Continue(Task t)
        {
            Console.WriteLine($"taskID:{Task.CurrentId} beginning! ---name:task3.continue");
            for (int i = 1; i <= 5; i++)
            {
                Thread.Sleep(500);
                Console.WriteLine($"{i.ToString()} ---name:task3.continue");
            }
            Console.WriteLine($"taskID:{Task.CurrentId} finished! ---name:task3.continue");
        }

        async static void task4()
        {
            Console.WriteLine($"taskID:{Task.CurrentId} beginning! ---name:task4");
            for (int i = 1; i<= 5; i++)
           {
              Console.WriteLine($"{i.ToString()} ---name:task4");
              await Task.Delay(500);
            }
            Console.WriteLine($"taskID:{Task.CurrentId} finished! ---name:task4");
        }

        static void Main(string[] args)
        {
            //-----------方式1-----------------
            Task task1 = new Task(() =>
            {
                Console.WriteLine($"taskID:{Task.CurrentId} beginning! ------name:task1");
                
                for(int i=1;i<=5;i++)
                {   
                    Thread.Sleep(500);
                    Console.WriteLine($"{i.ToString()} ---name:task1");
                }
                Console.WriteLine($"taskID:{Task.CurrentId} finished! ------name:task1");
            });
            task1.Start();

            // program execution after task1 finish
            task1.ContinueWith((task) =>
            {
                Console.WriteLine($"taskID:{task.Id}.continue begin and this task id is {Task.CurrentId}");
               
                for (int i = 1; i <= 5; i++)
                { 
                    Thread.Sleep(500);
                    Console.WriteLine($"{i.ToString()} ---name:task1.continue");
                }
                Console.WriteLine($"taskID:{Task.CurrentId} finished! ------name:task{task.Id}.continue");
            });

            //-------------方式2----------------
            var task2 = new Task(() => CallTask2("Task2"));
            task2.Start();

            //------------方式3------------
            Task task3 = new Task(CallTask3);
            task3.Start();
            Task task3Continue = task3.ContinueWith(CallTask3Continue);

            task3Continue.Wait(); // 阻塞主线程,直到task3Continue 线程执行结束
            //-------------方式4-------------
            task4();

            Console.ReadKey();
        }
    }
 }

输出结果为:

taskID:1 beginning! ------name:task1
taskID:3 beginning! ---name:Task2
taskID:4 beginning! ---name:task3
1 ---name:task1
1 ---name:task2
1 ---name:task3
2 ---name:task1
2 ---name:task2
2 ---name:task3
3 ---name:task1
3 ---name:task2
3 ---name:task3
4 ---name:task1
4 ---name:task3
4 ---name:task2
5 ---name:task1
taskID:1 finished! ------name:task1
taskID:1.continue begin and this task id is 2
5 ---name:task3
5 ---name:task2
taskID:4 finished! ---name:task3
taskID:3 finished! ---name:Task2
taskID:5 beginning! ---name:task3.continue
1 ---name:task1.continue
1 ---name:task3.continue
2 ---name:task1.continue
2 ---name:task3.continue
3 ---name:task3.continue
3 ---name:task1.continue
4 ---name:task3.continue
4 ---name:task1.continue
5 ---name:task3.continue
5 ---name:task1.continue
taskID:5 finished! ---name:task3.continue
taskID:2 finished! ------name:task1.continue
taskID: beginning! ---name:task4
1 ---name:task4
2 ---name:task4
3 ---name:task4
4 ---name:task4
5 ---name:task4
taskID: finished! ---name:task4

下面对输出结果进行分析:
直接看主函数部分,可以看到共有task1、task1.continue、task2、task3、task3.continue、task4六个子线程、分别用了四种方法:

task1 使用 : Task task1 = new Task(() =>{ } );直接去创建子线程。其实,这个运行的话可以简化即:
将下面代码:

Task task1 = new Task(() =>{ } );
task1.start()

换成 : Task.Run(() =>{ } ); 即可
task2 使用: var task2 = new Task(() => CallTask2("Task2")) 创建子线程。
task3 使用: Task task3 = new Task(CallTask3);直接创建子线程
task4 使用异步方法去创建子线程,关键词:async, 可以看到在task4之前,使用了task3Continue.Wait();  
这个语句可以用来阻塞主线程,直到task3Continue 线程执行结束后才会 task4线程的定义与运行。

另外,可以看到,在别的task使用延时用的都是 Thread.Sleep(500); 而使用异步方法创建的子线程在使用延时
的时候使用的是 await Task.Delay(500);这一点需要留意。
task1.continue 线程 即 task1.ContinueWith((task) => {})在task1 完全执行结束后才执行,
同理
task3.continue在task3 完全结束之后才执行。

Task.ContinueWith((task) => {})可以将子线程串联起来
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ZhangJingHuaJYO

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值