今天看啥
    热点:

      天发国际娱乐官网:昨天下午,中赫国安俱乐部顾问咨询委员会成立,第一届委员会由技术顾问、媒体顾问和球迷代表共20人组成,任期两年。

      菜鸟之旅——学习线程(2),之旅线程


        前面两篇回顾线程和线程池的使用方法,微软在.NET4.5推出了新的线程模型-Task。本篇将简单的介绍Task的使用方法。

      Task与线程

        Task与线程或者说线程池关系紧密,可以说是基于线程池实现的,虽说任务最终还是要抛给线程去执行,但是Task仍然会比线程、线程池的开销要小,并且提供了可靠的API来控制线任务执行。

        使用Task来执行的任务最终会交给线程池来执行,若该任务需要长时间执行,可以将其标记为LongRunning,这是便会单独去请求创建线程来执行该任务。

      Task

       创建

        Task的创建也存在两种方式,使用new或者使用静态工厂方式来创建:

              static void Main(string[] args)
              {
      
                  Task t = new Task(Menthod1);
                  t.Start();
      
                  Task.Factory.StartNew(Menthod2);
                  
                  Console.WriteLine("主线程的ID:{0}", Thread.CurrentThread.ManagedThreadId);
                  Console.WriteLine("--------------------");
                  Console.ReadLine();
              }
      
              static void Menthod1()
              {
                  Thread.Sleep(2000);
                  Console.WriteLine("线程1的ID:{0}", Thread.CurrentThread.ManagedThreadId);
                  Console.WriteLine("--------------------");
              }
              static void Menthod2()
              {
                  Thread.Sleep(4000);
                  Console.WriteLine("线程2的ID:{0}", Thread.CurrentThread.ManagedThreadId);
                  Console.WriteLine("--------------------");
              }

        上面说到使用Task执行任务最终还是需要线程池来执行,若不想让线程池来执行,可以添加LongRunning标志:

              Task t = new Task(Menthod1, TaskCreationOptions.LongRunning);
              t.Start();
      
              Task.Factory.StartNew(Menthod2, TaskCreationOptions.LongRunning);

         TaskCreationOptions还有很多枚举值,用来控制任务的更多属性。

       参数与返回值

        使用Task也可以传入参数(object类型)与返回值:

              static void Main(string[] args)
              {
      
                  Task.Factory.StartNew(Menthod1, 233);
                  //int result = Task.Factory.StartNew(new Func<object, int>(Menthod3), 233).Result;
                  Task<int> t = Task.Factory.StartNew(new Func<object, int>(Menthod3), 233);
                  int result = t.Result;
      
                  Console.WriteLine("主线程的ID:{0}", Thread.CurrentThread.ManagedThreadId);
                  Console.WriteLine("result:{0}", result);
                  Console.WriteLine("--------------------");
                  Console.ReadLine();
              }
      
              static void Menthod1(object obj)
              {
                  Thread.Sleep(2000);
                  Console.WriteLine("线程1的ID:{0}", Thread.CurrentThread.ManagedThreadId);
                  Console.WriteLine("obj:{0}", obj);
                  Console.WriteLine("--------------------");
              }
              static int Menthod3(object obj)
              {
                  Thread.Sleep(6000);
                  Console.WriteLine("线程3的ID:{0}", Thread.CurrentThread.ManagedThreadId);
                  Console.WriteLine("obj:{0}", obj);
                  Console.WriteLine("--------------------");
                  return obj;
              }

         这里为了获取返回值,阻塞了主线程,这里请注意一下。

       等待Task

        可以使用Task实例的Wait方法来实现等待任务结束,也可以向多线程一样,使用WaitAll和WaitAny一样来等待多个任务结束,不过操作更为简单:

              t.Wait();
              Task.WaitAll(t1, t2 ...);
              Task.WaitAny(t1, t2 ...);

       

       取消Task

        任务也是可以事先取消的,不过需要使用CancellationTokenSource:

              static void Main(string[] args)
              {
                  Task.Factory.StartNew(Menthod1);
      
                  CancellationTokenSource cancelTokenSource = new CancellationTokenSource();
                  Task.Factory.StartNew(Menthod2, cancelTokenSource.Token);
                  cancelTokenSource.Cancel();
      
                  Console.WriteLine("主线程的ID:{0}", Thread.CurrentThread.ManagedThreadId);
                  Console.WriteLine("--------------------");
                  Console.ReadLine();
              }

        上述代码就可以将线程2给取消掉,当然,Cancel方法可以自己找个合适的地方调用。

       

       继续Task

         在Task中,可以实现在一个任务结束后开启另一个新的任务:

              static void Main(string[] args)
              {
                  Task t = Task.Factory.StartNew(Menthod1);
                  t.ContinueWith(new Action<Task>(Menthod4));
      
                  Console.WriteLine("主线程的ID:{0}", Thread.CurrentThread.ManagedThreadId);
                  Console.WriteLine("任务t的ID:{0}", t.Id);
                  Console.WriteLine("--------------------");
                  Console.ReadLine();
              }
      
              static void Menthod1()
              {
                  Thread.Sleep(2000);
                  Console.WriteLine("线程1的ID:{0}", Thread.CurrentThread.ManagedThreadId);
                  Console.WriteLine("--------------------");
              }
              static void Menthod4(Task t)
              {
                  Console.WriteLine("线程4的ID:{0}", Thread.CurrentThread.ManagedThreadId);
                  Console.WriteLine("任务t的ID:{0}", t.Id);
                  Console.WriteLine("--------------------");
              }

        这里因为使用了委托,也可以使用lambda表达式,更简单一些调用:

              Task t = Task.Factory.StartNew(Menthod1);
              t.ContinueWith(task =>
              {
                  Console.WriteLine("线程4的ID:{0}", Thread.CurrentThread.ManagedThreadId);
                  Console.WriteLine("任务t的ID:{0}", task.Id);
                  Console.WriteLine("--------------------");
              });

        

      总结

        使用传统线程方式来进行多线程编程的时候,对线程的控制总是不到位,产生一些奇奇怪怪的问题;或是代码写得很杂乱;或是开发人员乱用线程,比方说无限制的创建线程、将线程池线程占满,等等。

        Task的出现,实现对传统线程操作的封装,提供可靠高效的API来控制线程,极大的方便多线程编程,所以可以用到Task的地方尽量使用Task;当然,这里仍会产生线程安全的问题,同样需要进行线程同步,与上一篇处理方式类似。

        Task的内容还有很多,更深层的运行原理、封装还等着我们去了解,现在只把我用到的东西分享出来,希望能帮助到需要的人。

        线程的学习就先告一段落了,敬请期待新的内容吧。

       

      www.1click-soft.comtruehttp://www.1click-soft.com/Asp_Netjc/1304227.htmlTechArticle菜鸟之旅——学习线程(2),之旅线程 前面两篇回顾线程和线程池的使用方法,微软在.NET4.5推出了新的线程模型-Task。本篇将简单的介绍...

      相关文章

      相关搜索: 线程

      帮客评论

      视觉看点
      百度 360 搜狗