C#学习笔记-多线程Task(任务)二

TaskCreationOptions的使用与了解

TaskCreationOptions是Task任务的一个枚举,当Task任务长时间运行时,建议在创建任务时,使用TaskCreationOptions.LongRunning

长时间的任务在ThreadPool中,如果长时间不归还线程,系统会强制开启一个新的线程,会一定程度的影响程序的性能

在使用TaskCreationOptions.AttachedToParent时,其作用相当于Task.WaitAll

  //
    // 摘要:
    //     指定用于控制任务的创建和执行的可选行为的标志。
    [Flags]
    public enum TaskCreationOptions
    {
        //
        // 摘要:
        //     指定应使用默认行为。
        None = 0,
        //
        // 摘要:
        //     提示 System.Threading.Tasks.TaskScheduler 以一种尽可能公平的方式安排任务,这意味着较早安排的任务将更可能较早运行,而较晚安排运行的任务将更可能较晚运行。
        PreferFairness = 1,
        //
        // 摘要:
        //     指定任务将是长时间运行的、粗粒度的操作,涉及比细化的系统更少、更大的组件。 它会向 System.Threading.Tasks.TaskScheduler
        //     提示,过度订阅可能是合理的。 可以通过过度订阅创建比可用硬件线程数更多的线程。 它还将提示任务计划程序:该任务需要附加线程,以使任务不阻塞本地线程池队列中其他线程或工作项的向前推动。
        LongRunning = 2,
        //
        // 摘要:
        //     指定将任务附加到任务层次结构中的某个父级。 默认情况下,子任务(即由外部任务创建的内部任务)将独立于其父任务执行。 可以使用 System.Threading.Tasks.TaskContinuationOptions.AttachedToParent
        //     选项以便将父任务和子任务同步。 请注意,如果使用 System.Threading.Tasks.TaskCreationOptions.DenyChildAttach
        //     选项配置父任务,则子任务中的 System.Threading.Tasks.TaskCreationOptions.AttachedToParent 选项不起作用,并且子任务将作为分离的子任务执行。
        //     有关详细信息,请参阅附加和分离的子任务。
        AttachedToParent = 4,
        //
        // 摘要:
        //     指定任何尝试作为附加的子任务执行(即,使用 System.Threading.Tasks.TaskCreationOptions.AttachedToParent
        //     选项创建)的子任务都无法附加到父任务,会改成作为分离的子任务执行。 有关详细信息,请参阅附加和分离的子任务。
        DenyChildAttach = 8,
        //
        // 摘要:
        //     防止环境计划程序被视为已创建任务的当前计划程序。 这意味着像 StartNew 或 ContinueWith 创建任务的执行操作将被视为 System.Threading.Tasks.TaskScheduler.Default
        //     当前计划程序。
        HideScheduler = 16,
        //
        // 摘要:
        //     强制异步执行添加到当前任务的延续任务。 请注意,System.Threading.Tasks.TaskCreationOptions.RunContinuationsAsynchronously
        //     成员在以 .NET Framework 4.6 开头的 System.Threading.Tasks.TaskCreationOptions 枚举中可用。
        RunContinuationsAsynchronously = 64
    }
    public static void Test8()
        {
            Task partentTask = Task.Factory.StartNew(() =>
              {
                  Task childTask1 = new Task(() =>
                    {
                        Thread.Sleep(1000);
                        //业务逻辑
                        Console.WriteLine("childTask1线程ID:" + Thread.CurrentThread.ManagedThreadId + "    " + "Time:" + DateTime.Now.ToString());
                    },TaskCreationOptions.AttachedToParent);
                  Task childTask2 = new Task(() =>
                  {
                      Thread.Sleep(3000);
                      //业务逻辑
                      Console.WriteLine("childTask2线程ID:" + Thread.CurrentThread.ManagedThreadId + "    " + "Time:" + DateTime.Now.ToString());
                  },TaskCreationOptions.AttachedToParent);
                  childTask1.Start();
                  childTask2.Start();
                 

              });
            partentTask.Wait();//相当于waitALL,等待所有子任务执行完成后执行其他任务
                               //业务逻辑
            //TaskCreationOptions.AttachedToParent如果这个枚举参数不添加,主线程会直接运行,不等待
            Console.WriteLine("partentTask线程ID:" + Thread.CurrentThread.ManagedThreadId + "    " + "Time:" + DateTime.Now.ToString());
        }
        //如果任务是长时间运行的,建议加上TaskCreationOptions.LongRunning,ThreadPool如果长时间不归还线程,系统会强制开启新的线程,会影响程序的性能。

Task任务的取消(CancellationTokenSource)

当Task任务执行取消,希望程序可以执行一些其他的任务,这时候可以通过CancellationTokenSource实例对象的Token.Resister方法来执行

应用场景:数据库连接超时自动取消,TCP自动重连等等

    public static void Test10()
        {
            CancellationTokenSource cts = new CancellationTokenSource();
            Task task =new Task(() =>
             {
                 while (!cts.IsCancellationRequested)
                 {
                     Thread.Sleep(500);

                     Console.WriteLine("Task线程id:"+Thread.CurrentThread.ManagedThreadId+"   "+"Time:"+DateTime.Now.ToString());
                 }
                 Console.WriteLine("Task线程id:"+Thread.CurrentThread.ManagedThreadId+"   " +"Time:"+DateTime.Now.ToString());
             },cts.Token);
            task.Start();
            cts.Token.Register(() =>
            {
                Console.WriteLine("正在执行清理。。。。");
                Thread.Sleep(2000);
                Console.WriteLine("清理完成");
            });
            Thread.Sleep(3000);
            cts.Cancel();//当cancel方法被执行了,会转向Token.Register方法的业务逻辑
        }
        //Task任务延时自动取消:比如我们请求一个远程接口,如果长时间没有返回数据,我们可以做一个时间限制,超时可以取消任务(比如微信红包退回)

        使用cts.CancelAfter(3000);//任务3s后自动取消,可以设置多少秒后自动取消

线程锁

在多线程中,必定会存在资源的竞争,使用线程锁可以使线程有效有序的访问资源

1、Lock是monitor的语法糖,本质上是解决资源的竞争,和资源锁定的问题

2、Lock锁住的资源不能是局部变量,要能被其他线程访问到

3、Lock不能锁住string类型

多线程还要其他的线程锁,这里简单描述一下Lock

没有使用线程锁的情况,资源无序访问


        private static object mylock=new object();
        static int num = 0;
        public static void Test15()
        {
            for(int i = 0; i < 5; i++)
            {
                Task task = Task.Factory.StartNew(() =>
                {
                    test34();
                });
            }         
        }

        public static void test34()
        {
            for(int i = 0; i < 100; i++)
            {
                lock (mylock) 
                {
                    num++;
                    Console.WriteLine(num);
                }              
            }
        }

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值