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) => {})可以将子线程串联起来
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
C#中的多线程任务(Task)是一种用于并行和异步编程的重要机制。它允许我们在应用程序中创建并发任务,从而提高性能和响应性。 在C#中,我们可以使用Task来创建和管理多线程任务。以下是使用Task进行多线程编程的一般步骤: 1. 创建一个Task对象:我们可以使用Task的静态方法来创建一个任务。例如,可以使用Task.Run方法创建一个简单的任务。示例代码如下: ```csharp Task task = Task.Run(() => { // 在此处执行任务操作 }); ``` 2. 定义任务操作:在创建任务时,我们通常需要定义要在任务中执行的操作。可以使用lambda表达式或方法来指定任务操作。示例代码如下: ```csharp Task task = Task.Run(() => { // 在此处执行任务操作 }); ``` 3. 等待任务完成:如果需要等待任务完成,可以使用Task的Wait方法或await关键字。这样可以确保在继续执行后续代码之前,任务已经完成。示例代码如下: ```csharp Task task = Task.Run(() => { // 在此处执行任务操作 }); task.Wait(); // 等待任务完成 // 或者使用 await 关键字: await task; ``` 4. 处理任务结果:如果任务有返回值,我们可以使用Task<T>泛型来创建带返回值的任务,并通过Result属性获取任务的结果。示例代码如下: ```csharp Task<int> task = Task.Run(() => { // 在此处执行任务操作并返回结果 return 42; }); int result = task.Result; // 获取任务的结果 ``` 总结起来,使用C#Task可以方便地实现多线程编程。我们可以创建、定义和等待任务,并处理任务的结果。这样可以实现并行执行任务,提高应用程序的性能和响应性。 提供了一个基于C#开发的工具库(MSCL超级工具库),其中包括了很多常用工具的封装。虽然它没有提到Task,但我们可以借助C#多线程编程机制来实现并发任务。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

ZhangJingHuaJYO

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

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

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

打赏作者

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

抵扣说明:

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

余额充值