zoukankan      html  css  js  c++  java
  • 多线程(4)Task

      使用线程池使得创建线程已经很简单了,但是使用线程池不支持线程的取消,完成和失败通知等交互操作,为了解决这些问题,.net 4.0带来了TPL(Task Parallel Library)任务并行库,下面就来总结下Task的使用。

    创建和运行任务

    在.net 4.0下使用task创建一个线程非常简单,有两种方式,如下代码:

     1 namespace ConsoleApplication19
     2 {
     3     class Program
     4     {
     5         static void Main(string[] args)
     6         {
     7             //方法1
     8             var task1 = new Task(() => 
     9             {
    10                 Console.WriteLine("Create and start task!");
    11             });
    12             task1.Start();
    13 
    14             //方法2
    15             Task.Factory.StartNew(() => 
    16             {
    17                 Console.WriteLine("Task factory start new task!");
    18             });
    19 
    20             Console.ReadKey();
    21         }
    22     }
    23 }
    View Code

    输出结果:

    需要注意的是:task也是基于线程池的,所以这两个任务的执行顺序是不固定的。 

    取消任务

     创建一个新的任务之后,我们随时都可以取消它,取消方法如下代码:

     1 namespace ConsoleApplication20
     2 {
     3     class Program
     4     {
     5         static void Main(string[] args)
     6         {
     7             Console.WriteLine("Main thread starting...");
     8 
     9             var cts = new CancellationTokenSource();
    10             var task1 = Task.Factory.StartNew(() =>
    11             {
    12                 TaskAction(cts.Token);
    13             });
    14 
    15             Thread.Sleep(3000);
    16             Console.WriteLine(string.Format("current task status::{0}", task1.Status));
    17 
    18             //取消任务
    19             cts.Cancel();
    20             Console.WriteLine("start cancel task!");
    21             for (int i = 0; i < 5; i++)
    22             {
    23                 Thread.Sleep(500);
    24                 Console.WriteLine(string.Format("current task status::{0}", task1.Status));
    25             }
    26 
    27             Console.WriteLine("Main thread completed!");
    28             Console.ReadKey();
    29         }
    30 
    31         public static void TaskAction(CancellationToken token)
    32         {
    33             Console.WriteLine("Sub thread starting...");
    34 
    35             while (true)
    36             {
    37                 Thread.Sleep(1000);
    38                 if (token.IsCancellationRequested)
    39                 {
    40                     Console.WriteLine("Sub thread be cancelled!");
    41                     return;
    42                 }
    43                 Console.WriteLine("Sub thread is running!");
    44             }
    45         }
    46 
    47     }
    48 }
    View Code

     输出结果:

    创建任务集合并输出结果 

    如下代码:

     1 namespace ConsoleApplication21
     2 {
     3     class Program
     4     {
     5         static void Main(string[] args)
     6         {
     7             //创建任务集合并输出结果
     8             var tasks = new List<Task<string>>();
     9 
    10             var task1 = Task.Factory.StartNew<string>(() => 
    11             {
    12                 Console.WriteLine("task1 running on thread id:"+ Thread.CurrentThread.ManagedThreadId);
    13                 return "task1";
    14             });
    15             tasks.Add(task1);
    16 
    17             var task2 = Task.Factory.StartNew<string>(() =>
    18             {
    19                 Console.WriteLine("task2 running on thread id:" + Thread.CurrentThread.ManagedThreadId);
    20                 return "task2";
    21             });
    22             tasks.Add(task2);
    23 
    24             var task3 = Task.Factory.StartNew<string>(() => 
    25             {
    26                 Console.WriteLine("task3 running on thread id:" + Thread.CurrentThread.ManagedThreadId);
    27                 return "task3";
    28             });
    29             tasks.Add(task3);
    30 
    31             //输出结果
    32             foreach (var item in tasks)
    33             {
    34                 Console.WriteLine(item.Result);//调用Task的Result方法相当于调用了Task.WaitAll(tasks.ToArray());
    35             }
    36 
    37             Console.ReadKey(); 
    38         }
    39     }
    40 }

    输出结果:

    这里要注意2点:

    1,每个任务会开启一个新的线程,并且运行顺序不固定。

    2,Task.Result相当于调用了Wait方法,等待异步任务完成。

    多任务的串行化

     如下代码:

     1 namespace ConsoleApplication22
     2 {
     3     class Program
     4     {
     5         static void Main(string[] args)
     6         {
     7             //多任务的串行化
     8             var task1 = Task.Factory.StartNew(() => 
     9             {
    10                 Console.WriteLine("start task1...");
    11                 Console.WriteLine("current thread id:"+ Thread.CurrentThread.ManagedThreadId);
    12             });
    13 
    14             var task2 = task1.ContinueWith((item) => 
    15             {
    16                 Console.WriteLine("start task2...");
    17                 Console.WriteLine("current thread id:" + Thread.CurrentThread.ManagedThreadId);
    18             });
    19 
    20             var task3 = task2.ContinueWith((item)=>
    21             {
    22                 Console.WriteLine("start task3...");
    23                 Console.WriteLine("current thread id:" + Thread.CurrentThread.ManagedThreadId);
    24             });
    25 
    26             Console.ReadKey();
    27         }
    28     }
    29 }

     输出结果:

    注意,多任务串行化后,就相当于顺序执行了,而且有可能使用的是同一个线程,从上图的thread id就可以看出来。

    多任务等待执行完成

    如下代码:

     1 namespace ConsoleApplication23
     2 {
     3     class Program
     4     {
     5         static void Main(string[] args)
     6         {
     7             //多任务等待执行完成
     8             var tasks = new List<Task<string>>();
     9 
    10             var task1 = Task.Factory.StartNew<string>(() => 
    11             {
    12                 Console.WriteLine("task1");
    13                 return "task1";
    14             });
    15             tasks.Add(task1);
    16 
    17             var task2 = Task.Factory.StartNew<string>(() => 
    18             {
    19                 Console.WriteLine("task2");
    20                 return "task2";
    21             });
    22             tasks.Add(task2);
    23 
    24             var task3 = Task.Factory.StartNew<string>(() => 
    25             {
    26                 Console.WriteLine("task3");
    27                 return "task3";
    28             });
    29             tasks.Add(task3);
    30 
    31             //等待所有任务完成
    32             Task.WaitAll(tasks.ToArray());
    33 
    34             //等价于下面的调用
    35             //foreach (var item in tasks)
    36             //{
    37             //    item.Result
    38             //}
    39 
    40             Console.ReadKey();
    41         }
    42     }
    43 }

    输出结果:

    需要注意的是,如果是有返回值的task,可以使用Task.Result获取返回值的同时,也在等待Task执行完成,相当于调用了Task.Wait方法。

    创建子任务

    如下代码:

     1 namespace ConsoleApplication24
     2 {
     3     class Program
     4     {
     5         static void Main(string[] args)
     6         {
     7             //创建子任务
     8             var parentTask = Task.Factory.StartNew(() => 
     9             {
    10                 Console.WriteLine("parent task!");
    11                 var childTask = Task.Factory.StartNew(() => 
    12                 {
    13                     Console.WriteLine("child task!");
    14                 }, TaskCreationOptions.AttachedToParent);
    15             });
    16 
    17             Console.ReadKey();
    18         }
    19     }
    20 }

    输出结果:

  • 相关阅读:
    C#变量初始化
    Mcrosoft中间语言的主要特征
    去除json数据的某些键值对
    ASP.NET MVC 之控制器与视图之间的数据传递
    ASP.NET MVC 路由进阶(之二)--自定义路由约束
    ASP.NET WEB API 初探
    Linux学习三部曲(之三)
    Linux学习三部曲(之二)
    Linux学习三部曲(之一)
    C# 3.0 特性之扩展方法
  • 原文地址:https://www.cnblogs.com/mcgrady/p/7055436.html
Copyright © 2011-2022 走看看