zoukankan      html  css  js  c++  java
  • 线程池任务

    线程池和任务

     
    1.  线程池

      1. 线程池基础
        • 创建线程和销毁线程是一个昂贵的操作,要耗费大量的时间。由于操作系统必须调度可运行的线程并执行上线文切换,所以太多的线程还对性能不利。
          为了改善这个情况,clr包含了代码来管理他自己的线程池。
          线程池是你的应用程序能使用的线程集合。
          线程池内部会维护一个 操作请求队列。应用程序执行一个异步请求操作时,将一个记录项(entry)追加到线程池的队列中。线程池的代码从这个对立中
          提取记录项,将这个记录项派发(dispatch)给一个线程池线程。
          当线程池完成任务后,线程不会被销毁。相反,线程会回到线程池,在哪里进入空闲状态,等待相应另一个请求。由于线程不销毁自身,所以不在再产生额外的性能损失;
      2. 我们来演示以线程池的方式异步的调用一个方法 
        复制代码
        public static void MainThreadPool()
                {
                    Console.WriteLine("主线程异步操作队列");
                    ThreadPool.QueueUserWorkItem(ThreadProc);
        
                    Console.WriteLine("主线程做其他工作");
                    Thread.Sleep(1000);//模拟其他工作
        
                    Console.WriteLine("主线程运行结束");
        
                    Console.ReadLine();
                }
        
                /// <summary>
                /// 与委托WaitCallback 签名相同的回掉方法 
                /// </summary>
                /// <param name="stateInfo">如果使用的是QueueUserWorkItem(WaitCallback callBack),该参数默认为null</param>
                static void ThreadProc(Object stateInfo)
                {
                    Console.WriteLine("线程池工作线程执行回掉");
                    Thread.Sleep(1000); //模拟其他工作
                }
        复制代码

        输出:

    1. 任务

      1. 很容易使用ThreadPool的QueueUserWorkItem方法发起一次异步的计算限制操作。但这个技术有许多限制。最大的问题是没有内置的机制 让你知道操作在什么时候完成,也没有机制在操作完成时得到返回值。为了克服这些限制(并解决其他一些问题),微软引入了任务的概念。
        通过using System.Threading.Tasks 命名空间中的类型来使用任务。
      2. 创建任务 
        复制代码
        public static void RunGetStartTask()
                {
                    //创建方式之一 :通过task的构造函数
                    Task t1 = new Task(Task1);
                    //创建方式之二:通过task工厂调用StartNew 创建并并启用
                    Task t2 = Task.Factory.StartNew(Task2);
        
                    Console.WriteLine("t1任务Start之前状态:{0},t2任务状态:{1}", t1.Status, t2.Status);
                    t1.Start();
                    Console.WriteLine("t1任务Start之后状态:{0},t2任务状态:{1}", t1.Status, t2.Status);
                    
                    Task.WaitAll(t1, t2);
        
                    Console.WriteLine("主线程执行完毕");
                    Console.WriteLine("t1最终状态:{0},t2最终状态:{1}", t1.Status, t2.Status);
                    Console.ReadLine();
                }
                public static void Task1()
                {
                    Thread.Sleep(1000);
                    Console.WriteLine("运行task1");
                }
                public static void Task2()
                {
                    Thread.Sleep(2000);
                    Console.WriteLine("运行task2");
                }
        复制代码

        输出

      3. 理解任务状态和生命周期   
        • task实例的执行取决于底层硬件和运行时可用的资源。因此,在您获取了有关task实例的任何信息后,这个状态可能会发生改变,因为task实例的状态也在同时发生改变。当task到达它的3种可能的最终之一时,它再也回不去之前的任何状态了,如图所示。
        • T初始状态:task实例有3种可能的初始状态,详细说明如图
        • 最终状态:接下来,task实例可以转换到running状态,并且最终转变到一个最终状态。
          如果task实例有关联的子任务,那么就不能认为这个task完成了,并且这个task将转变到WaitingForChildrenToComplete 状态。当task实例的子任务都完成后,这个Task将进入3种可能的最终状态之一。详细说明如下如图
      4. 取消任务
        • 如果想中断task实例的执行,可以通过取消标记(Cancellation Token)
        • CancellationTokenSource 能够初始化取消的请求,而CancellationToken能够将这些请求传递给异步的操作。 
      5. 复制代码
        public static void RunGetStartTaskCancel()
                {
                    var cts = new CancellationTokenSource();
                    var ct = cts.Token;
        
                    var sw = Stopwatch.StartNew();
                    var t1 = Task.Factory.StartNew(() => Task1Cancel(ct), ct);
        
                    var t2 = Task.Factory.StartNew(() => Task2Cancel(ct), ct);
                    //主线程模拟1秒
                    Thread.Sleep(1000);
        
                    cts.Cancel();
        
                    try
                    {
                        if (!Task.WaitAll(new Task[] { t1, t2 }, 3000))
                        {
                            Console.WriteLine("Task1Cancel 和 Task2Cancel 超过了2秒完成.");
                            Console.WriteLine("t1状态" + t1.Status.ToString());
                            Console.WriteLine("t2状态" + t2.Status.ToString());
                            Console.ReadLine();
                        }
                        Console.ReadLine();
        
                    }
                    catch (AggregateException ex)
                    {
                        foreach (Exception innerException in ex.InnerExceptions)
                        {
                            Debug.WriteLine(innerException.ToString());
                            Console.WriteLine("异常消息:" + innerException.ToString());
                        }
        
                        if (t1.IsCanceled)
                        {
                            Console.WriteLine("t1 task 运行Task1Cancel 已取消");
                        }
        
                        if (t1.IsCanceled)
                        {
                            Console.WriteLine("t2 task 运行Task2Cancel 已取消");
                        }
        
                        Console.WriteLine("耗时" + sw.Elapsed.ToString());
                        Console.WriteLine("完成");
                        Console.ReadLine();
        
                    }
                }
                public static void Task1Cancel(CancellationToken ct)
                {
                    ct.ThrowIfCancellationRequested();
                    var sw = Stopwatch.StartNew();
                    Thread.Sleep(1000); 
        
                    Console.WriteLine("运行task1");
                    Console.WriteLine("task1:" + sw.Elapsed.ToString());
                    ct.ThrowIfCancellationRequested();
                }
                public static void Task2Cancel(CancellationToken ct)
                {
                    ct.ThrowIfCancellationRequested();
                    var sw = Stopwatch.StartNew();
                    Thread.Sleep(2000);
        
                    Console.WriteLine("运行task2");
                    Console.WriteLine("task2:" + sw.Elapsed.ToString());
                }
        复制代码
      6. 从任务获取返回值
        • 目前,我们的任务实例还没有返回值,他们都是运行一些不返回值的委托。正如开头将的,任务是可以有返回值的。通过使用Task<TResult>实例,其中TResult要替换为返回类型。
          复制代码
          public static void RunGetStartTaskResult()
                  {
                      var t1 = Task.Factory.StartNew(() => GetTask1("ChengTian"));
                      //等待t1 完成
                      t1.Wait();
                      var t2 = Task.Factory.StartNew(() =>
                      {
                          for (int i = 0; i < t1.Result.Count; i++)
                          {
                              Console.WriteLine(t1.Result[i]);
                          }
          
                      });
          
                      Console.WriteLine("结束");
                      Console.ReadLine();
                  }
          
                  public static List<char> GetTask1(string ss)
                  {
                      Thread.Sleep(1000);
                      return ss.ToList();
                  }
          复制代码

          输出返回值 

      7. 通过延续串联任务 
        • 改造下上面的例子,在t1任务完成之后启动t2任务
      8. 复制代码
        public static void RunGetStartTaskContinueWith()
                {
                    var t1 = Task.Factory.StartNew(() => GetTask1("ChengTian"));
                    var t2 = t1.ContinueWith(t =>
                    {
                        for (int i = 0; i < t1.Result.Count; i++)
                        {
                            Console.WriteLine(t1.Result[i]);
                        }
        
                    });
        
                    Console.WriteLine("结束");
                    Console.ReadLine();
                }
        复制代码

        可以在任何任务实例上调用ContinueWith方法,创建一个延续。 你也可以串联很多任务,然后等待最后一个任务(在这个实例中为t2)执行完成.                 

  • 相关阅读:
    Solr学习笔记(5)—— Spring Data Solr入门
    Redis学习笔记(6)——SpringDataRedis入门
    SpringDataRedis java.net.UnknownHostException: 127.0.0.1 错误
    Spring Security 入门
    基于Laravel框架下使用守护进程supervisor实现定时任务(毫秒)
    laravel框架中Job和事件event的解析
    Laravel源码解析之model(代码)
    Laravel框架下路由的使用(源码解析)
    Laravel服务容器的绑定与解析
    laravel框架中超实用的功能介绍
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/7198649.html
Copyright © 2011-2022 走看看