C#多线程编程Task用法详解

目录
  • 一、基本概念
    • Task优势
  • 二、Task用法
    • 创建任务
      • 1、使用Task创建无返回值
      • 2、使用Task.Run方法创建任务
      • 3、使用Factory方式创建任务
      • 4、创建带返回值的Task
  • 三、常见方法
    • 1、WaitAll()
    • 2、WaitAny()
    • 3、ContinueWhenAll()
    • 4、ContinueWhenAny
    • 5、ContinueWith

一、基本概念

Task优势

ThreadPool相比Thread来说具备了很多优势,但是ThreadPool却又存在一些使用上的不方便,例如:

  • ThreadPool不支持线程的取消、完成、失败通知等交互性操作;
  • ThreadPool不支持线程执行的先后次序;

.NET Framework 在4.0的时候提供了一个功能更强大的概念:Task。Task在ThreadPool的基础上进行了优化,并提供了更多的API。看下面一个简单的示例:

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

namespace TaskDemo
{
    class Program
    {
        static void Main(string[] args)
        {
            // 创建Task
            Task t = new Task(() =>
            {
                Console.WriteLine("任务开始工作.....");
                Thread.Sleep(5000);
            });
            // 启动
            t.Start();
            t.ContinueWith((task) =>
            {
                Console.WriteLine("任务完成,完成时候的状态为:");
                Console.WriteLine("IsCanceled={0}\tIsCompleted={1}\tIsFaulted={2}", task.IsCanceled, task.IsCompleted, task.IsFaulted);
            });
            Console.WriteLine("启动");
            Console.ReadKey();
        }
    }
}

二、Task用法

创建任务

Task创建的任务可以分为有返回值和无返回值两种。

1、使用Task创建无返回值

先看一下Task的定义:

可以看到Task构造函数的参数是Action委托。所以使用Task创建任务的代码如下:

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

namespace TaskDemo
{
    class Program
    {
        static void Main(string[] args)
        {

            #region 1、使用Task创建任务
            Task task = new Task(() => TaskMethod("Task 1"));
            Console.WriteLine("before start status:"+task.Status);
            // Task创建的任务必须调用start方法才能启动
            task.Start();
            Console.WriteLine("after start status:" + task.Status);
            #endregion
            Console.ReadKey();
        }

        static void TaskMethod(string name)
        {
            Console.WriteLine("Task {0} is running on a thread id {1}. Is thread pool thread: {2}",
                name, Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.IsThreadPoolThread);
        }
    }
}

程序运行结果:

注:任务的状态,Start之前为Created,Start之后为WaitingToRun。

2、使用Task.Run方法创建任务

Task.Run创建的任务可以执行启动:

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

namespace TaskDemo
{
    class Program
    {
        static void Main(string[] args)
        {

            #region 1、使用Task创建任务
            //Task task = new Task(() => TaskMethod("Task 1"));
            //Console.WriteLine("before start status:"+task.Status);
            //// Task创建的任务必须调用start方法才能启动
            //task.Start();
            //Console.WriteLine("after start status:" + task.Status);
            #endregion

            #region 2、使用Task.Run创建任务
            Task.Run(() => TaskMethod("Task Run"));
            #endregion
            Console.ReadKey();
        }

        static void TaskMethod(string name)
        {
            Console.WriteLine("Task {0} is running on a thread id {1}. Is thread pool thread: {2}",
                name, Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.IsThreadPoolThread);
        }
    }
}

程序运行结果:

3、使用Factory方式创建任务

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

namespace TaskDemo
{
    class Program
    {
        static void Main(string[] args)
        {

            #region 1、使用Task创建任务
            //Task task = new Task(() => TaskMethod("Task 1"));
            //Console.WriteLine("before start status:"+task.Status);
            //// Task创建的任务必须调用start方法才能启动
            //task.Start();
            //Console.WriteLine("after start status:" + task.Status);
            #endregion

            #region 2、使用Task.Run创建任务
            // Task.Run(() => TaskMethod("Task Run"));
            #endregion

            #region 3、使用Factory创建任务
            // 使用Task.Factory创建
            Task.Factory.StartNew(() => TaskMethod("Task 4"));
            //标记为长时间运行任务,则任务不会使用线程池,而在单独的线程中运行。
            Task.Factory.StartNew(() => TaskMethod("Task 5"), TaskCreationOptions.LongRunning);

            // 实例化TaskFactory对象,然后创建
            TaskFactory factory = new TaskFactory();
            factory.StartNew(() => TaskMethod("Task 6"));

            #endregion
            Console.ReadKey();
        }

        static void TaskMethod(string name)
        {
            Console.WriteLine("Task {0} is running on a thread id {1}. Is thread pool thread: {2}",
                name, Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.IsThreadPoolThread);
        }
    }
}

程序运行结果:

4、创建带返回值的Task

代码如下:

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

namespace TaskDemo
{
    class Program
    {
        static void Main(string[] args)
        {

            #region 1、使用Task创建任务
            //Task task = new Task(() => TaskMethod("Task 1"));
            //Console.WriteLine("before start status:"+task.Status);
            //// Task创建的任务必须调用start方法才能启动
            //task.Start();
            //Console.WriteLine("after start status:" + task.Status);
            #endregion

            #region 2、使用Task.Run创建任务
            // Task.Run(() => TaskMethod("Task Run"));
            #endregion

            #region 3、使用Task.Factory创建任务
            //Task.Factory.StartNew(() => TaskMethod("Task 4"));
            ////标记为长时间运行任务,则任务不会使用线程池,而在单独的线程中运行。
            //Task.Factory.StartNew(() => TaskMethod("Task 5"), TaskCreationOptions.LongRunning);
            #endregion

            #region 4、创建带返回值的任务
            TaskMethodReturn("Main Thread Task");
            // 创建带返回值的Task
            Task<int> task = CreateTask("Task 1");
            // 启动
            task.Start();
            // 获取返回值
            int result1 = task.Result;
            Console.WriteLine($"Task 1 Result is:{result1}");
            Task<int> task2 = new Task<int>(() => TaskMethodReturn("Task 2"));
            task2.Start();
            int result2 = task2.Result;
            Console.WriteLine($"Task 2 Result is:{result2}");
            int result3= Task.Run<int>(() => TaskMethodReturn("Task 3")).Result;
            Console.WriteLine($"Task 3 Result is:{result3}");
            int result4 = Task.Factory.StartNew<int>(() => TaskMethodReturn("Task 4")).Result;
            Console.WriteLine($"Task 4 Result is:{result4}");
            #endregion
            Console.ReadKey();
        }

        /// <summary>
        /// 返回一个Task<int>
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        static Task<int> CreateTask(string name)
        {
            // 参数是Func<int>
            return new Task<int>(() => TaskMethodReturn(name));
        }

        static void TaskMethod(string name)
        {
            Console.WriteLine("Task {0} is running on a thread id {1}. Is thread pool thread: {2}",
                name, Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.IsThreadPoolThread);
        }

        static int TaskMethodReturn(string name)
        {
            Console.WriteLine("Task {0} is running on a thread id {1}. Is thread pool thread: {2}",
                   name, Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.IsThreadPoolThread);
            Thread.Sleep(TimeSpan.FromSeconds(2));
            return 42;
        }
    }
}

程序运行结果:

我们在文章开始的时候说过,Task是基于ThreadPool的,那么怎么证明呢?看下面的代码:

/// <summary>
/// 测试Task的线程来自于ThreadPool
/// </summary>
static void Test()
{
            // 设置线程池中最大的线程数
            ThreadPool.SetMaxThreads(6, 6);
            // 创建Task的集合
            List<Task> taskList = new List<Task>();
            // 创建int类型的集合,用于存放线程ID
            List<int> threadIdList = new List<int>();
            // 使用Task循环创建50个线程
            for (int i = 0; i < 30; i++)
            {
                int k = i;
                Task task = Task.Run(() =>
                {
                    // 当前线程ID加入到集合中
                    threadIdList.Add(Thread.CurrentThread.ManagedThreadId);
                    Console.WriteLine($"this is {k} 循环 ThreadID:{Thread.CurrentThread.ManagedThreadId.ToString("00")}");
                    // 休眠
                    Thread.Sleep(200);
                });
                // 把task加入到集合中
                taskList.Add(task);
            }

            // 等待所有的线程执行完
            Task.WaitAll(taskList.ToArray());
            // 输出总数量
            Console.WriteLine($"线程总数:{threadIdList.Distinct().Count()}");
}

程序运行结果:

从结果中可以看出,Task中的线程确实是来自于ThreadPool。

三、常见方法

我们以下面的一个例子来讲解Task中比较常见的几个方法。多名开发者合作开发一个项目,每个人负责一个模块的开发,我们可以把这个过程认为是多线程,代码如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;

namespace TaskDemo
{
    class Program
    {
        static void Main(string[] args)
        {

            #region 1、使用Task创建任务
            //Task task = new Task(() => TaskMethod("Task 1"));
            //Console.WriteLine("before start status:"+task.Status);
            //// Task创建的任务必须调用start方法才能启动
            //task.Start();
            //Console.WriteLine("after start status:" + task.Status);
            #endregion

            #region 2、使用Task.Run创建任务
            // Task.Run(() => TaskMethod("Task Run"));
            #endregion

            #region 3、使用Factory创建任务
            // 使用Task.Factory创建
            //Task.Factory.StartNew(() => TaskMethod("Task 4"));
            ////标记为长时间运行任务,则任务不会使用线程池,而在单独的线程中运行。
            //Task.Factory.StartNew(() => TaskMethod("Task 5"), TaskCreationOptions.LongRunning);

            // 实例化TaskFactory对象,然后创建
            //TaskFactory factory = new TaskFactory();
            //factory.StartNew(() => TaskMethod("Task 6"));
            #endregion

            #region 4、创建带返回值的任务
            //TaskMethodReturn("Main Thread Task");
            //// 创建带返回值的Task
            //Task<int> task = CreateTask("Task 1");
            //// 启动
            //task.Start();
            //// 获取返回值
            //int result1 = task.Result;
            //Console.WriteLine($"Task 1 Result is:{result1}");
            //Task<int> task2 = new Task<int>(() => TaskMethodReturn("Task 2"));
            //task2.Start();
            //int result2 = task2.Result;
            //Console.WriteLine($"Task 2 Result is:{result2}");
            //int result3= Task.Run<int>(() => TaskMethodReturn("Task 3")).Result;
            //Console.WriteLine($"Task 3 Result is:{result3}");
            //int result4 = Task.Factory.StartNew<int>(() => TaskMethodReturn("Task 4")).Result;
            //Console.WriteLine($"Task 4 Result is:{result4}");
            #endregion

            #region 测试Task线程是来自于ThreadPool

            // Test();
            #endregion

            // 合作开发项目,每个人负责一个模块,可以认为是多线程
            Console.WriteLine("开始合作开发一个大项目!");
            Task.Run(() => CodingShow("Tom", "搭建微服务架构!"));
            Task.Run(() => CodingShow("Kevin", "微信接口!"));
            Task.Run(() => CodingShow("Jack", "搭建后台框架!"));
            Task.Run(() => CodingShow("Alex", "设计数据库!"));
            Task.Run(() => CodingShow("Lee", "支付宝接口对接!"));

            Console.ReadKey();
        }

        /// <summary>
        /// 返回一个Task<int>
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        static Task<int> CreateTask(string name)
        {
            // 参数是Func<int>
            return new Task<int>(() => TaskMethodReturn(name));
        }

        static void TaskMethod(string name)
        {
            Console.WriteLine("Task {0} is running on a thread id {1}. Is thread pool thread: {2}",
                name, Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.IsThreadPoolThread);
        }

        static int TaskMethodReturn(string name)
        {
            Console.WriteLine("Task {0} is running on a thread id {1}. Is thread pool thread: {2}",
                   name, Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.IsThreadPoolThread);
            Thread.Sleep(TimeSpan.FromSeconds(2));
            return 42;
        }

        /// <summary>
        /// 测试Task的线程来自于ThreadPool
        /// </summary>
        static void Test()
        {
            // 设置线程池中最大的线程数
            ThreadPool.SetMaxThreads(6, 6);
            // 创建Task的集合
            List<Task> taskList = new List<Task>();
            // 创建int类型的集合,用于存放线程ID
            List<int> threadIdList = new List<int>();
            // 使用Task循环创建50个线程
            for (int i = 0; i < 30; i++)
            {
                int k = i;
                Task task = Task.Run(() =>
                {
                    // 当前线程ID加入到集合中
                    threadIdList.Add(Thread.CurrentThread.ManagedThreadId);
                    Console.WriteLine($"this is {k} 循环 ThreadID:{Thread.CurrentThread.ManagedThreadId.ToString("00")}");
                    // 休眠
                    Thread.Sleep(200);
                });
                // 把task加入到集合中
                taskList.Add(task);
            }

            // 等待所有的线程执行完
            Task.WaitAll(taskList.ToArray());
            // 输出总数量
            Console.WriteLine($"线程总数:{threadIdList.Distinct().Count()}");
        }

        /// <summary>
        /// 模拟Coding过程
        /// </summary>
        /// <param name="name"></param>
        /// <param name="projectName"></param>
        static void CodingShow(string name, string projectName)
        {
            Console.WriteLine($"CodingShow Start  {name} {projectName}  {Thread.CurrentThread.ManagedThreadId.ToString("00")} ");
            long lResult = 0;
            for (int i = 0; i < 1_000_000_000; i++)
            {
                lResult += i;
            }

            Console.WriteLine($"CodingShow   End  {name} {projectName} {Thread.CurrentThread.ManagedThreadId.ToString("00")} ");
        }
    }
}

程序运行结果:

这时需求发生了变化,所有的模块都开发完成以后,开始搭建测试环境,修改代码如下:

// 合作开发项目,每个人负责一个模块,可以认为是多线程
Console.WriteLine("开始合作开发一个大项目!");
Task.Run(() => CodingShow("Tom", "搭建微服务架构!"));
Task.Run(() => CodingShow("Kevin", "微信接口!"));
Task.Run(() => CodingShow("Jack", "搭建后台框架!"));
Task.Run(() => CodingShow("Alex", "设计数据库!"));
Task.Run(() => CodingShow("Lee", "支付宝接口对接!"));
Console.WriteLine("所有模块都开发完成,开始搭建测试环境");

程序运行结果:

可以看到显然不是我们想要的结果,模块开发工作还没有结束就搭建测试环境,即子线程还没有结束,主线程就已经结束了。要想实现我们想要的效果,那么必须使主线程等待所有子线程都结束以后,主线程才能结束。

1、WaitAll()

WaitAll()表示等待所有的Task都执行完成。看WaitAll()的定义:

WaitAll()方法有很多重载,我们在这里使用第一个重载方法,即参数是Task[]数组。查看Run()方法的定义时,我们会发现Run()方法的返回值就是Task类型,我们使用WaitAll()修改上面的代码:

// 定义一个Task类型的集合
List<Task> taskList = new List<Task>();
Console.WriteLine("开始合作开发一个大项目!");
taskList.Add(Task.Run(() => CodingShow("Tom", "搭建微服务架构!")));
taskList.Add(Task.Run(() => CodingShow("Kevin", "微信接口!")));
taskList.Add(Task.Run(() => CodingShow("Jack", "搭建后台框架!")));
taskList.Add(Task.Run(() => CodingShow("Alex", "设计数据库!")));
taskList.Add(Task.Run(() => CodingShow("Lee", "支付宝接口对接!")));

// 等待所有模块都开发完成,才能搭建测试环境
Task.WaitAll(taskList.ToArray());
Console.WriteLine("所有模块都开发完成,开始搭建测试环境");

程序运行结果:

WaitAll()会使程序产生卡顿。

加载首页信息的时候可以使用WaitAll()方法。一个首页信息可能来自于几部分的数据,每一部分的数据对应一个线程,只有所有的线程都执行完毕才显示首页信息。

2、WaitAny()

这时需求又发生改变了:某一个模块开发完成以后就搭建测试环境。这时候就可以使用WaitAny()了。WaitAny()表示等待其中任何一个任务完成就会进入下一个任务,定义如下:

修改后的代码如下:

// 定义一个Task类型的集合
List<Task> taskList = new List<Task>();
Console.WriteLine("开始合作开发一个大项目!");
taskList.Add(Task.Run(() => CodingShow("Tom", "搭建微服务架构!")));
taskList.Add(Task.Run(() => CodingShow("Kevin", "微信接口!")));
taskList.Add(Task.Run(() => CodingShow("Jack", "搭建后台框架!")));
taskList.Add(Task.Run(() => CodingShow("Alex", "设计数据库!")));
taskList.Add(Task.Run(() => CodingShow("Lee", "支付宝接口对接!")));

// 等待所有模块都开发完成,才能搭建测试环境
Task.WaitAny(taskList.ToArray());
Console.WriteLine("有模块开发完成,开始搭建测试环境");

程序运行结果:

可以看到:设计数据库模块完成以后,就开始搭建测试环境了。如何需求。

WaitAny()会使程序产生卡顿。

有一个列表数据,数据可以来源于接口、缓存、数据库等,可以开启多个线程,只要有一个线程执行完毕就可以继续执行下面的步骤,这时就可以使用WaitAny()。

3、ContinueWhenAll()

WaitAll()会卡顿界面,那么有没有不卡顿界面的呢?ContinueWhenAll和WaitAll实现的效果一样,代码如下:

List<Task> taskList = new List<Task>();
Console.WriteLine("开始合作开发一个大项目!");
taskList.Add(Task.Run(() => CodingShow("Tom", "搭建微服务架构!")));
taskList.Add(Task.Run(() => CodingShow("Kevin", "微信接口!")));
taskList.Add(Task.Run(() => CodingShow("Jack", "搭建后台框架!")));
taskList.Add(Task.Run(() => CodingShow("Alex", "设计数据库!")));
taskList.Add(Task.Run(() => CodingShow("Lee", "支付宝接口对接!")));
TaskFactory factory = new TaskFactory();
factory.ContinueWhenAll(taskList.ToArray(), t => Console.WriteLine("所有模块开发完成"));

程序运行结果:

4、ContinueWhenAny

ContinueWhenAny实现的效果和WaitAny一样,ContinueWhenAny不会卡顿界面,代码如下:

List<Task> taskList = new List<Task>();
Console.WriteLine("开始合作开发一个大项目!");
taskList.Add(Task.Run(() => CodingShow("Tom", "搭建微服务架构!")));
taskList.Add(Task.Run(() => CodingShow("Kevin", "微信接口!")));
taskList.Add(Task.Run(() => CodingShow("Jack", "搭建后台框架!")));
taskList.Add(Task.Run(() => CodingShow("Alex", "设计数据库!")));
taskList.Add(Task.Run(() => CodingShow("Lee", "支付宝接口对接!")));
TaskFactory factory = new TaskFactory();
factory.ContinueWhenAny(taskList.ToArray(), t => Console.WriteLine("某一个模块开发完成"));

程序运行结果:

ContinueWhenAll()和ContinueWhenAny()都会开启一个新的线程。

5、ContinueWith

ContinueWith表示回调,代码如下:

Task.Run(() => { Console.WriteLine("任务执行完成"); }).ContinueWith(p=>
{
      Task.Run(() => { Console.WriteLine("执行回调"); });
});

程序执行结果:

程序完整代码如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;

namespace TaskDemo
{
    class Program
    {
        static void Main(string[] args)
        {

            #region 1、使用Task创建任务
            //Task task = new Task(() => TaskMethod("Task 1"));
            //Console.WriteLine("before start status:"+task.Status);
            //// Task创建的任务必须调用start方法才能启动
            //task.Start();
            //Console.WriteLine("after start status:" + task.Status);
            #endregion

            #region 2、使用Task.Run创建任务
            // Task.Run(() => TaskMethod("Task Run"));
            #endregion

            #region 3、使用Factory创建任务
            // 使用Task.Factory创建
            //Task.Factory.StartNew(() => TaskMethod("Task 4"));
            ////标记为长时间运行任务,则任务不会使用线程池,而在单独的线程中运行。
            //Task.Factory.StartNew(() => TaskMethod("Task 5"), TaskCreationOptions.LongRunning);

            // 实例化TaskFactory对象,然后创建
            //TaskFactory factory = new TaskFactory();
            //factory.StartNew(() => TaskMethod("Task 6"));
            #endregion

            #region 4、创建带返回值的任务
            //TaskMethodReturn("Main Thread Task");
            //// 创建带返回值的Task
            //Task<int> task = CreateTask("Task 1");
            //// 启动
            //task.Start();
            //// 获取返回值
            //int result1 = task.Result;
            //Console.WriteLine($"Task 1 Result is:{result1}");
            //Task<int> task2 = new Task<int>(() => TaskMethodReturn("Task 2"));
            //task2.Start();
            //int result2 = task2.Result;
            //Console.WriteLine($"Task 2 Result is:{result2}");
            //int result3= Task.Run<int>(() => TaskMethodReturn("Task 3")).Result;
            //Console.WriteLine($"Task 3 Result is:{result3}");
            //int result4 = Task.Factory.StartNew<int>(() => TaskMethodReturn("Task 4")).Result;
            //Console.WriteLine($"Task 4 Result is:{result4}");
            #endregion

            #region 测试Task线程是来自于ThreadPool

            // Test();
            #endregion

            // 合作开发项目,每个人负责一个模块,可以认为是多线程
            // 无序
            //Console.WriteLine("开始合作开发一个大项目!");
            //Task.Run(() => CodingShow("Tom", "搭建微服务架构!"));
            //Task.Run(() => CodingShow("Kevin", "微信接口!"));
            //Task.Run(() => CodingShow("Jack", "搭建后台框架!"));
            //Task.Run(() => CodingShow("Alex", "设计数据库!"));
            //Task.Run(() => CodingShow("Lee", "支付宝接口对接!"));
            //Console.WriteLine("所有模块都开发完成,开始搭建测试环境");

            #region WaitAll
            //// 定义一个Task类型的集合
            //List<Task> taskList = new List<Task>();
            //Console.WriteLine("开始合作开发一个大项目!");
            //taskList.Add(Task.Run(() => CodingShow("Tom", "搭建微服务架构!")));
            //taskList.Add(Task.Run(() => CodingShow("Kevin", "微信接口!")));
            //taskList.Add(Task.Run(() => CodingShow("Jack", "搭建后台框架!")));
            //taskList.Add(Task.Run(() => CodingShow("Alex", "设计数据库!")));
            //taskList.Add(Task.Run(() => CodingShow("Lee", "支付宝接口对接!")));

            //// 等待所有模块都开发完成,才能搭建测试环境
            //Task.WaitAll(taskList.ToArray());
            //Console.WriteLine("所有模块都开发完成,开始搭建测试环境");
            #endregion

            #region WaitAny
            // 定义一个Task类型的集合
            //List<Task> taskList = new List<Task>();
            //Console.WriteLine("开始合作开发一个大项目!");
            //taskList.Add(Task.Run(() => CodingShow("Tom", "搭建微服务架构!")));
            //taskList.Add(Task.Run(() => CodingShow("Kevin", "微信接口!")));
            //taskList.Add(Task.Run(() => CodingShow("Jack", "搭建后台框架!")));
            //taskList.Add(Task.Run(() => CodingShow("Alex", "设计数据库!")));
            //taskList.Add(Task.Run(() => CodingShow("Lee", "支付宝接口对接!")));

            //// 等待所有模块都开发完成,才能搭建测试环境
            //Task.WaitAny(taskList.ToArray());
            //Console.WriteLine("有模块开发完成,开始搭建测试环境");
            #endregion

            #region ContinueWhenAll
            //List<Task> taskList = new List<Task>();
            //Console.WriteLine("开始合作开发一个大项目!");
            //taskList.Add(Task.Run(() => CodingShow("Tom", "搭建微服务架构!")));
            //taskList.Add(Task.Run(() => CodingShow("Kevin", "微信接口!")));
            //taskList.Add(Task.Run(() => CodingShow("Jack", "搭建后台框架!")));
            //taskList.Add(Task.Run(() => CodingShow("Alex", "设计数据库!")));
            //taskList.Add(Task.Run(() => CodingShow("Lee", "支付宝接口对接!")));
            //TaskFactory factory = new TaskFactory();
            //factory.ContinueWhenAll(taskList.ToArray(), t => Console.WriteLine("所有模块开发完成"));
            #endregion

            #region ContinueWhenAll
            //List<Task> taskList = new List<Task>();
            //Console.WriteLine("开始合作开发一个大项目!");
            //taskList.Add(Task.Run(() => CodingShow("Tom", "搭建微服务架构!")));
            //taskList.Add(Task.Run(() => CodingShow("Kevin", "微信接口!")));
            //taskList.Add(Task.Run(() => CodingShow("Jack", "搭建后台框架!")));
            //taskList.Add(Task.Run(() => CodingShow("Alex", "设计数据库!")));
            //taskList.Add(Task.Run(() => CodingShow("Lee", "支付宝接口对接!")));
            //TaskFactory factory = new TaskFactory();
            //factory.ContinueWhenAny(taskList.ToArray(), t => Console.WriteLine("某一个模块开发完成"));
            #endregion

            #region ContinueWith
            Task.Run(() => { Console.WriteLine("任务执行完成"); }).ContinueWith(p=>
            {
               Task.Run(() => { Console.WriteLine("执行回调"); });
            });
            #endregion

            Console.ReadKey();
        }

        /// <summary>
        /// 返回一个Task<int>
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        static Task<int> CreateTask(string name)
        {
            // 参数是Func<int>
            return new Task<int>(() => TaskMethodReturn(name));
        }

        static void TaskMethod(string name)
        {
            Console.WriteLine("Task {0} is running on a thread id {1}. Is thread pool thread: {2}",
                name, Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.IsThreadPoolThread);
        }

        static int TaskMethodReturn(string name)
        {
            Console.WriteLine("Task {0} is running on a thread id {1}. Is thread pool thread: {2}",
                   name, Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.IsThreadPoolThread);
            Thread.Sleep(TimeSpan.FromSeconds(2));
            return 42;
        }

        /// <summary>
        /// 测试Task的线程来自于ThreadPool
        /// </summary>
        static void Test()
        {
            // 设置线程池中最大的线程数
            ThreadPool.SetMaxThreads(6, 6);
            // 创建Task的集合
            List<Task> taskList = new List<Task>();
            // 创建int类型的集合,用于存放线程ID
            List<int> threadIdList = new List<int>();
            // 使用Task循环创建50个线程
            for (int i = 0; i < 30; i++)
            {
                int k = i;
                Task task = Task.Run(() =>
                {
                    // 当前线程ID加入到集合中
                    threadIdList.Add(Thread.CurrentThread.ManagedThreadId);
                    Console.WriteLine($"this is {k} 循环 ThreadID:{Thread.CurrentThread.ManagedThreadId.ToString("00")}");
                    // 休眠
                    Thread.Sleep(200);
                });
                // 把task加入到集合中
                taskList.Add(task);
            }

            // 等待所有的线程执行完
            Task.WaitAll(taskList.ToArray());
            // 输出总数量
            Console.WriteLine($"线程总数:{threadIdList.Distinct().Count()}");
        }

        /// <summary>
        /// 模拟Coding过程
        /// </summary>
        /// <param name="name"></param>
        /// <param name="projectName"></param>
        static void CodingShow(string name, string projectName)
        {
            Console.WriteLine($"CodingShow Start  {name} {projectName}  {Thread.CurrentThread.ManagedThreadId.ToString("00")} ");
            long lResult = 0;
            for (int i = 0; i < 1_000_000_000; i++)
            {
                lResult += i;
            }

            Console.WriteLine($"CodingShow   End  {name} {projectName} {Thread.CurrentThread.ManagedThreadId.ToString("00")} ");
        }
    }
}

到此这篇关于C#多线程编程Task用法的文章就介绍到这了。希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • C#利用Task实现任务超时多任务一起执行的方法

    前言 其实Task跟线程池ThreadPool的功能类似,不过写起来更为简单,直观.代码更简洁了,使用Task来进行操作.可以跟线程一样可以轻松的对执行的方法进行控制. 创建Task有两种方式,一种是使用构造函数创建,另一种是使用 Task.Factory.StartNew 进行创建. 如下代码所示 1.使用构造函数创建Task Task t1 = new Task(MyMethod); 2.使用Task.Factory.StartNew 进行创建Task Task t1 = Task.Fact

  • C#如何使用Task执行异步操作

    为什么要使用 Task 线程是创建并发的底层工具,因此具有一定的局限性. 没有简单的方法可以从联合(Join)线程得到"返回值".因此必须创建一些共享域.当抛出一个异常时,捕捉和处理异常也是麻烦的. 线程完成之后,无法再次启动该线程.相反,只能联合(Join)它(在进程阻塞当前线程). 任务是可组合的--使用延续将它们串联在一起.它们可以使用线程池减少启动延迟,而且它们可以通过TaskCompletionSource使用回调方法,避免多个线程同时等待I/O密集操作. Task 和 Th

  • C# 并行和多线程编程——Task进阶知识

    一.Task的嵌套 Task中还可以再嵌套Task,Thread中能不能这样做,我只能说我是没这样写过.Task中的嵌套,我感觉其实也可以分开来写,不过嵌套起来会方便管理一点.Task中的嵌套分为两种,关联嵌套和非关联嵌套,就是说内层的Task和外层的Task是否有联系,下面我们编写代码先来看一下非关联嵌套,及内层Task和外层Task没有任何关系,还是在控制台程序下面,代码如下: static void Main(string[] args) { var pTask = Task.Factor

  • C#多线程学习之Thread、ThreadPool、Task、Parallel四者区别

    目录 Thread ThreadPool Task Parallel Task专讲 线程(英语:thread)是操作系统能够进行运算调度的最小单位.它被包含在进程之中,是进程中的实际运作单位.一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务.进程是资源分配的基本单位.所有与该进程有关的资源,都被记录在进程控制块PCB中.以表示该进程拥有这些资源或正在使用它们.本文以一些简单的小例子,简述多线程的发展历程[Thread,ThreadPool,Task

  • C# 并行和多线程编程——认识和使用Task

    对于多线程,我们经常使用的是Thread.在我们了解Task之前,如果我们要使用多核的功能可能就会自己来开线程,然而这种线程模型在.net 4.0之后被一种称为基于"任务的编程模型"所冲击,因为task会比thread具有更小的性能开销,不过大家肯定会有疑惑,任务和线程到底有什么区别呢? 任务和线程的区别: 1.任务是架构在线程之上的,也就是说任务最终还是要抛给线程去执行. 2.任务跟线程不是一对一的关系,比如开10个任务并不是说会开10个线程,这一点任务有点类似线程池,但是任务相比线

  • C# task应用实例详解

    Task的应用 ​Task的MSDN的描述如下: [Task类的表示单个操作不会返回一个值,通常以异步方式执行. Task对象是一种的中心思想基于任务的异步模式首次引入.NETFramework 4 中. 因为由执行工作Task对象通常以异步方式执行线程池线程上而不是以同步方式在主应用程序线程中,可以使用Status属性,并将IsCanceled, IsCompleted,和IsFaulted属性,以确定任务的状态. 大多数情况下,lambda 表达式用于指定该任务所执行的工作量. 对于返回值的

  • 深入分析C# Task

    ​Task的MSDN的描述如下: [Task类的表示单个操作不会返回一个值,通常以异步方式执行. Task对象是一种的中心思想基于任务的异步模式首次引入.NETFramework 4 中. 因为由执行工作Task对象通常以异步方式执行线程池线程上而不是以同步方式在主应用程序线程中,可以使用Status属性,并将IsCanceled, IsCompleted,和IsFaulted属性,以确定任务的状态. 大多数情况下,lambda 表达式用于指定该任务所执行的工作量. 对于返回值的操作,您使用Ta

  • C#多线程编程Task用法详解

    目录 一.基本概念 Task优势 二.Task用法 创建任务 1.使用Task创建无返回值 2.使用Task.Run方法创建任务 3.使用Factory方式创建任务 4.创建带返回值的Task 三.常见方法 1.WaitAll() 2.WaitAny() 3.ContinueWhenAll() 4.ContinueWhenAny 5.ContinueWith 一.基本概念 Task优势 ThreadPool相比Thread来说具备了很多优势,但是ThreadPool却又存在一些使用上的不方便,例

  • Java多线程编程综合案例详解

    目录 Java多线程综合案例 数字加减 生产电脑 竞争抢答 Java多线程综合案例 数字加减 设计4个线程对象,两个线程执行减操作,两个线程执行加操作 public class ThreadDemo{ public static void main(String[] args) throws Exception { Resource res=new Resource(); AddThread at=new AddThread(res); SubThread st=new SubThread(re

  • Python多线程原理与用法详解

    本文实例讲述了Python多线程原理与用法.分享给大家供大家参考,具体如下: 多线程(英语:multithreading),是指从软件或者硬件上实现多个线程并发执行的技术.具有多线程能力的计算机因有硬件支持而能够在同一时间执行多于一个线程,进而提升整体处理性能.具有这种能力的系统包括对称多处理机.多核心处理器以及芯片级多处理(Chip-level multithreading)或同时多线程(Simultaneous multithreading)处理器.[1] 在一个程序中,这些独立运行的程序片

  • C#多线程系列之async和await用法详解

    目录 async和await async await 从以往知识推导 创建异步任务 创建异步任务并返回Task 异步改同步 说说awaitTask 说说 asyncTask<TResult> 同步异步? Task封装异步任务 关于跳到await变异步 为什么出现一层层的await async和await async 微软文档:使用 async 修饰符可将方法.lambda 表达式或匿名方法指定为异步. 使用 async 修饰的方法,称为异步方法. 例如: 为了命名规范,使用 async 修饰的

  • C#多线程用法详解

    目录 一.基本概念 1.进程 2.线程 二.多线程 2.1 System.Threading.Thread类 2.2线程的常用属性 2.2.1 线程的标识符 2.2.2 线程的优先级别 2.2.3 线程的状态 2.2.4 System.Threading.Thread的方法 2.3 前台线程和后台线程 2.4 线程同步 2.5 跨线程访问 2.6 终止线程 三.同步和异步 四.回调 一.基本概念 1.进程 首先打开任务管理器,查看当前运行的进程: 从任务管理器里面可以看到当前所有正在运行的进程.

  • C#异步编程async/await用法详解

    异步函数简介 一般指 async 修饰符声明得.可包含await表达式得方法或匿名函数. 声明方式 异步方法的声明语法与其他方法完全一样, 只是需要包含 async 关键字.async可以出现在返回值之前的任何位置, 如下示例: async public static void GetInfoAsync() { //... } public async static void GetInfoAsync() { //... } public static async void GetInfoAsy

  • 对python 多线程中的守护线程与join的用法详解

    多线程:在同一个时间做多件事 守护线程:如果在程序中将子线程设置为守护线程,则该子线程会在主线程结束时自动退出,设置方式为thread.setDaemon(True),要在thread.start()之前设置,默认是false的,也就是主线程结束时,子线程依然在执行. thread.join():在子线程完成运行之前,该子线程的父线程(一般就是主线程)将一直存在,也就是被阻塞 实例: #!/usr/bin/python # encoding: utf-8 import threading fro

  • Shell编程之变量的高级用法详解

    变量替换 语法 说明 ${变量名#匹配规则} 从变量开头进行规则匹配,将符合最短的数据删除 ${变量名##匹配规则} 从变量开头进行规则匹配,将符合最长的数据删除 ${变量名%匹配规则} 从变量尾部进行规则匹配,将符合最短的数据删除 ${变量名%%匹配规则} 从变量尾部进行规则匹配,将符合最长的数据删除 ${变量名/旧字符串/新字符串} 变量内容符合就字符串,则第一个旧字符串会被新字符串替换 ${变量名//旧字符串/新字符串} 变量内容符合就字符串,则全部的旧字符串会被新字符串替换 示例 var

  • C# Invoke,begininvoke的用法详解

    一直对invoke和begininvoke的使用和概念比较混乱,这两天看了些资料,对这两个的用法和原理有了些新的认识和理解. 首先说下,invoke和begininvoke的使用有两种情况: 1. control中的invoke.begininvoke. 2. delegrate中的invoke.begininvoke. 这两种情况是不同的,我们这里要讲的是第1种.下面我们在来说下.NET中对invoke和begininvoke的官方定义. control.invoke(参数delegate)方

  • Java RandomAccessFile的用法详解

    RandomAccessFile RandomAccessFile是用来访问那些保存数据记录的文件的,你就可以用seek( )方法来访问记录,并进行读写了.这些记录的大小不必相同:但是其大小和位置必须是可知的.但是该类仅限于操作文件. RandomAccessFile不属于InputStream和OutputStream类系的.实际上,除了实现DataInput和 DataOutput接口之外(DataInputStream和DataOutputStream也实现了这两个接口),它和这两个类系毫

随机推荐