zoukankan      html  css  js  c++  java
  • C# Task详解(学习)

    原文地址:C# Task详解 - 五维思考 - 博客园 (cnblogs.com)

    1. Task 的优势

      ThreadPool 相对于 Thread 具备许多优势,但 ThreadPool 却又存在一些使用上的不方便。

      比如:

        ThreadPool 不支持线程的取消、完成、失败通知等交互性操作。

        ThreadPool 不支持线程执行的先后次序。

      以前,开发者要实现上述功能,需要完成很多额外的工作,现在,FCL中提供了一个功能更强大的概念:Task。Task 在线程池的基础上进行了优化,并提供了更多的API。在FCL4.0中,编写多线程程序,Task显然已经优于传统的方式。

      简单的Demo: 

     1 using System;
     2 using System.Threading;
     3 using System.Threading.Tasks;
     4 
     5 namespace TaskDemo
     6 {
     7     class Program
     8     {
     9         static void Main(string[] args)
    10         {
    11             Task t = new Task(() =>
    12             {
    13                 Console.WriteLine($"{DateTime.Now}  任务开始工作...");
    14                 // 模拟工作过程
    15                 Thread.Sleep(5000);
    16             });
    17             t.Start();
    18             t.ContinueWith((task) =>
    19             {
    20                 Console.WriteLine($"{DateTime.Now}  任务完成,完成时的状态:");
    21                 Console.WriteLine("IsCanceled={0}	IsCompleted={1}	IsFaulted={2}", task.IsCanceled, task.IsCompleted, task.IsFaulted);
    22             });
    23             Console.ReadKey();
    24         }
    25     }
    26 }

    2. Task 用法

    2.1 创建任务

    2.1.1 无返回值的方式

    方式1:

    1 var t1 = new Task(()=>TaskMethod("Task 1"));
    2 t1.Start();
    3 Task.WaitAll(t1);    // 等待所有任务结束
    4 // 注:任务的状态
    5 //    Start 之前为Created
    6 //    Start 之后为 WaitingToRun

    方式2:

    1 Task.Run(()=>TaskMethod("Task 2"));

    方式3:

    1 Task.Factory.StartNew(()=>TaskMethod("Task 3"));    // 直接异步的方法
    2 // 或者
    3 var t3 = Task.Factory.StartNew(()=>TaskMethod("Task 3"));
    4 Task.WaitAll(t3);    // 等待所有任务结束
    5 // 任务的状态:
    6 // Start 之前:Running
    7 // Start 之后:Running

    示例:

     1 using System;
     2 using System.Threading;
     3 using System.Threading.Tasks;
     4 
     5 namespace TaskDemo
     6 {
     7     class Program
     8     {
     9        
    10         static void Main(string[] args)
    11         {
    12             
    13 
    14             #region Demo2
    15             var t1 = new Task(()=> TaskMethod("Task 1"));
    16             var t2 = new Task(()=> TaskMethod("Task 2"));
    17             t2.Start();
    18             t1.Start();
    19             Task.WaitAll(t1,t2);
    20             //Task.Run(()=>TaskMethod("Task 3"));   // 提示不包含该方法定义
    21             Task.Factory.StartNew(()=>TaskMethod("Task 4"));
    22             // 标记为长时间运行任务,则任务不会使用线程池,而在单独的线程中运行
    23             Task.Factory.StartNew(()=>TaskMethod("Task 5"), TaskCreationOptions.LongRunning);
    24 
    25             #region 常规使用方式
    26             Console.WriteLine("主线程执行业务处理。");
    27             // 创建任务
    28             Task task = new Task(()=>
    29             {
    30                 Console.WriteLine("使用 System.Threading.Tasks.Task 执行异步操作。");
    31                 for (int i = 0; i < 10; i++)
    32                 {
    33                     Console.WriteLine(i);
    34                 }
    35             });
    36             // 启动任务,并安排到当前任务队列线程中执行任务(System.Threading.Tasks.TaskScheduler)
    37             task.Start();
    38             Console.WriteLine("主线程执行其他处理。");
    39             task.Wait();
    40             #endregion
    41 
    42             Thread.Sleep(TimeSpan.FromSeconds(1));
    43             Console.ReadLine();
    44             #endregion
    45         }
    46 
    47         static void TaskMethod(string name)
    48         {
    49             Console.WriteLine("Task {0} is running on a thread id {1}. Is thread pool thread: {2}",
    50                 name, Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.IsThreadPoolThread);
    51         }
    52     }
    53 }

    两次运行不同的执行结果:

     asyn/await 的实现方式:

     1 using System;
     2 using System.Threading.Tasks;
     3 
     4 namespace AsyncAwaitDemo
     5 {
     6     class Program
     7     {
     8         static void Main(string[] args)
     9         {
    10             Console.WriteLine("主线程执行业务处理。");
    11             AsyncFunction();
    12             Console.WriteLine("主线程执行其他处理。");
    13             for (int i = 0; i < 10; i++)
    14             {
    15                 Console.WriteLine(string.Format("Main: i = {0}", i));
    16             }
    17             Console.ReadLine();
    18         }
    19 
    20         async static void AsyncFunction()
    21         {
    22             await Task.Delay(1);
    23             Console.WriteLine("使用 System.Threading.Tasks.Task 执行异步操作。");
    24             for (int i = 0; i < 10; i++)
    25             {
    26                 Console.WriteLine(string.Format("AsyncFunction: i = {0}", i));
    27             }
    28         }
    29     }
    30 }

    执行结果:

     

     将 await Task.Delay(1); 移动到 AsyncFunction 方法的最后,执行结果:

     (二)带返回值的方式

    方式4:

    1 Task<int> task = CreateTask("Task 1");
    2 task.Start();
    3 int result = task.Result;

    示例:

     1 using System;
     2 using System.Threading;
     3 using System.Threading.Tasks;
     4 
     5 namespace TaskDemo
     6 {
     7     class Program
     8     {
     9 
    10         static void Main(string[] args)
    11         { #region Demo3
    12             TaskMethod("Main Thread Task");
    13 
    14             Task<int> task = CreateTask("Task 1");
    15             task.Start();
    16             int result = task.Result;
    17             Console.WriteLine("Task 1 Result is : {0}", result);
    18 
    19             task = CreateTask("Task 2");
    20             // 该任务会运行在主线程中
    21             task.RunSynchronously();
    22             result = task.Result;
    23             Console.WriteLine("Task 2 Result is : {0}", result);
    24 
    25             task = CreateTask("Task 3");
    26             Console.WriteLine(task.Status);
    27             task.Start();
    28 
    29             while (!task.IsCompleted)
    30             {
    31                 Console.WriteLine(task.Status);
    32                 Thread.Sleep(TimeSpan.FromSeconds(0.5));
    33             }
    34 
    35             Console.WriteLine(task.Status);
    36             result = task.Result;
    37             Console.WriteLine("Task 3 Result is : {0}", result);
    38 
    39             #region 常规使用方式
    40             // 创建任务
    41             Task<int> getsumtask = new Task<int>(()=>GetSum());
    42             // 启动任务,并安排到当前任务队列线程中执行任务(System.Threading.Tasks.TaskScheduler)
    43             getsumtask.Start();
    44             Console.WriteLine("主线程执行其他处理");
    45             // 等待任务的完成执行过程。
    46             getsumtask.Wait();
    47             // 获得任务的执行结果
    48             Console.WriteLine("任务执行结果: {0}", getsumtask.Result.ToString());
    49             #endregion
    50 
    51             Console.ReadLine();
    52             #endregion
    53         }
    54 
    55         static Task<int> CreateTask(string name)
    56         {
    57             return new Task<int>(() => TaskMethod(name));
    58         }
    59 
    60         static int TaskMethod(string name)
    61         {
    62             Console.WriteLine("["+DateTime.Now +"]Task {0} is running on a thread id {1}. Is thread pool thread: {2}",
    63                 name, Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.IsThreadPoolThread);
    64             Thread.Sleep(TimeSpan.FromSeconds(2));
    65             return 42;
    66         }
    67 
    68         static int GetSum()
    69         {
    70             int sum = 0;
    71             Console.WriteLine("使用 Task 执行异步操作。");
    72             for (int i = 0; i < 100; i++)
    73             {
    74                 sum += i;
    75             }
    76             return sum;
    77         }
    78             
    79     }
    80 }

    执行结果:

     async / await 的实现

     1 using System;
     2 using System.Threading.Tasks;
     3 
     4 namespace TaskDemo
     5 {
     6     class Program
     7     {
     8         public static void Main()
     9         {
    10             var ret1 = AsyncGetsum();
    11             Console.WriteLine($"[{DateTime.Now}]主线程执行其他处理。");
    12             for (int i = 1; i <= 3; i++)
    13                 Console.WriteLine($"[{DateTime.Now}]Call Main()");
    14             int result = ret1.Result;                  //阻塞主线程
    15             Console.WriteLine("["+DateTime.Now+"]任务执行结果:{0}", result);
    16         }
    17 
    18         async static Task<int> AsyncGetsum()
    19         {
    20             await Task.Delay(1);
    21             int sum = 0;
    22             Console.WriteLine($"[{DateTime.Now}]使用 Task 执行异步操作");
    23             for (int i = 0; i < 100; i++)
    24             {
    25                 sum += i;
    26             }
    27             return sum;
    28         }
    29     }
    30 }

    执行结果:

     2.2 组合任务  ContinueWith

    简单Demo:

     1 using System;
     2 using System.Threading.Tasks;
     3 
     4 namespace ContiuneWithDemo
     5 {
     6     class Program
     7     {
     8         static void Main(string[] args)
     9         {
    10             #region Demo1
    11             // 创建一个任务
    12             Task<int> task = new Task<int>(() =>
    13             {
    14                 int sum = 0;
    15                 Console.WriteLine("使用 Task 执行异步操作。");
    16                 for (int i = 0; i < 100; i++)
    17                 {
    18                     sum += i;
    19                 }
    20                 return sum;
    21             });
    22             // 启动任务,并安排到当前任务队列线程中执行任务(System.Threading.Tasks.TaskScheduler)
    23             task.Start();
    24             // 任务完成时执行处理。
    25             Task cwt = task.ContinueWith(t =>
    26             {
    27                 Console.WriteLine("任务完成后的执行结果:{0}", t.Result.ToString());
    28             });
    29             task.Wait();
    30             cwt.Wait();
    31             Console.ReadKey();
    32             #endregion
    33         }
    34     }
    35 }

    执行结果:

     任务的串行:

     1 ConcurrentStack<int> stack = new ConcurrentStack<int>();
     2 // t1 先串行
     3 var t1 = Task.Factory.StartNew(() =>
     4 {
     5    stack.Push(1);
     6    stack.Push(2);
     7 });
     8 // t2,t3 并行执行
     9 var t2 = t1.ContinueWith(t =>
    10 {
    11    int result;
    12    stack.TryPop(out result);
    13    Console.WriteLine("Task t2 result={0}, Thread id {1}", result, Thread.CurrentThread.ManagedThreadId);
    14 });
    15 // t2,t3 并行执行
    16 var t3 = t1.ContinueWith(t =>
    17 {
    18    int result;
    19    stack.TryPop(out result);
    20    Console.WriteLine("Task t3 result={0}, Thread id {1}", result, Thread.CurrentThread.ManagedThreadId);
    21 });
    22 // 等待 t2 和 t3 执行完
    23 Task.WaitAll(t2, t3);
    24 // t4 串行执行
    25 var t4 = Task.Factory.StartNew(() =>
    26 {
    27    Console.WriteLine("当前集合元素个数:{0}, Thread id {1}", stack.Count, Thread.CurrentThread.ManagedThreadId);
    28 });
    29 t4.Wait();
    30 
    31 Console.ReadKey();

     执行结果:

    子任务:

     1 using System;
     2 using System.Threading.Tasks;
     3 
     4 namespace ContiuneWithDemo
     5 {
     6     class Program
     7     {
     8         static void Main(string[] args)
     9         {
    10             Task<string[]> parent = new Task<string[]>(state =>
    11             {
    12                 Console.WriteLine(state);
    13                 string[] result = new string[2];
    14                 // 创建并启动子任务
    15                 new Task(() => { result[0] = "我是子任务1。"; }, TaskCreationOptions.AttachedToParent).Start();
    16                 new Task(() => { result[1] = "我是子任务2。"; }, TaskCreationOptions.AttachedToParent).Start();
    17                 return result;
    18             }, "我是父任务,并在我的处理过程中创建多个子任务,所有子任务完成以后我才会结束执行。");
    19             // 任务处理完成后执行的操作
    20             parent.ContinueWith(t => { Array.ForEach(t.Result, r => Console.WriteLine(r)); });
    21             // 启动父任务
    22             parent.Start();
    23             // 等待任务结束 Wait 只能等待父线程结束,没办法等到父线程的 ContinueWith 结束
    24             parent.Wait();
    25             Console.ReadLine();   
    26         }
    27     }
    28 }     

    执行结果:

     动态并行(TaskCreationOptions.AttachedToParent)父任务等待所有子任务完成后,整个任务才算完成

     1 using System;
     2 using System.Collections.Concurrent;
     3 using System.Threading;
     4 using System.Threading.Tasks;
     5 
     6 namespace ContiuneWithDemo
     7 {
     8     class Program
     9     {
    10         static void Main(string[] args)
    11         {
    12             Node root = GetNode();
    13             DisplayTree(root);
    14             Console.ReadKey();
    15          }
    16  
    17         class Node
    18         {
    19             public Node Left { get; set; }
    20             public Node Right { get; set; }
    21             public string Text { get; set; }
    22         }
    23 
    24         static Node GetNode()
    25         {
    26             Node root = new Node
    27             {
    28                 Left = new Node
    29                 {
    30                     Left = new Node
    31                     {
    32                         Text = "L-L"
    33                     },
    34                     Right = new Node
    35                     {
    36                         Text = "L-R"
    37                     },
    38                     Text = "L"
    39                 },
    40                 Right = new Node
    41                 {
    42                     Left = new Node
    43                     {
    44                         Text = "R-L"
    45                     },
    46                     Right = new Node
    47                     {
    48                         Text = "R-R"
    49                     },
    50                     Text = "R"
    51                 },
    52                 Text = "Root"
    53             };
    54             return root;
    55         }
    56 
    57         static void DisplayTree(Node root)
    58         {
    59             var task = Task.Factory.StartNew(()=>DisplayNode(root),
    60                 CancellationToken.None,
    61                 TaskCreationOptions.None,
    62                 TaskScheduler.Default);
    63             task.Wait();
    64         }
    65 
    66         static void DisplayNode(Node current)
    67         {
    68             if (current.Left != null)
    69             {
    70                 Task.Factory.StartNew(()=>DisplayNode(current.Left),
    71                     CancellationToken.None,
    72                     TaskCreationOptions.AttachedToParent,
    73                     TaskScheduler.Default);
    74             }
    75             if (current.Right != null)
    76             {
    77                 Task.Factory.StartNew(()=>DisplayNode(current.Right),
    78                     CancellationToken.None,
    79                     TaskCreationOptions.AttachedToParent,
    80                     TaskScheduler.Default);
    81             }
    82             Console.WriteLine("当前节点的值为{0};处理的 ThreadId = {1}", current.Text, Thread.CurrentThread.ManagedThreadId);
    83         }
    84     }
    85 }

    执行结果:

    2.3 取消任务 CancellationTokenSource

     1 using System;
     2 using System.Threading;
     3 using System.Threading.Tasks;
     4 
     5 namespace CanellationTokenSourceDemo
     6 {
     7     class Program
     8     {
     9         static void Main(string[] args)
    10         {
    11             var cts = new CancellationTokenSource();
    12             var longTask = new Task<int>(()=>TaskMethod("Task 1", 10, cts.Token), cts.Token);
    13             Console.WriteLine(longTask.Status);
    14             cts.Cancel();
    15             Console.WriteLine(longTask.Status);
    16             Console.WriteLine("First task has been canelled before execution.");
    17             cts = new CancellationTokenSource();
    18             longTask = new Task<int>(()=>TaskMethod("Task 2", 10, cts.Token), cts.Token);
    19             longTask.Start();
    20             for (int i = 0; i < 5; i++)
    21             {
    22                 Thread.Sleep(TimeSpan.FromSeconds(0.5));
    23                 Console.WriteLine(longTask.Status);
    24             }
    25             cts.Cancel();
    26             for (int i = 0; i < 5; i++)
    27             {
    28                 Thread.Sleep(TimeSpan.FromSeconds(0.5));
    29                 Console.WriteLine(longTask.Status);
    30             }
    31             Console.WriteLine("A task has been completed with result {0}.", longTask.Result);
    32             Console.ReadKey();
    33         }
    34 
    35         private static int TaskMethod(string name, int seconds, CancellationToken token)
    36         {
    37             Console.WriteLine("Task {0} is running on a thread id {1}. Is thread pool thread: {2}",
    38                 name, Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.IsThreadPoolThread);
    39             for (int i = 0; i < seconds; i++)
    40             {
    41                 Thread.Sleep(TimeSpan.FromSeconds(1));
    42                 if (token.IsCancellationRequested)
    43                 {
    44                     return -1;
    45                 }
    46             }
    47             return 42 * seconds;
    48         }
    49     }
    50 }
  • 相关阅读:
    质数
    解决Winform中ListView.TopItem设置的问题
    证书格式简介及不同格式之间的转换方式
    Postgresql如何清理pg_xlog
    VirtualBox 4.2 released !
    ImportError: No module named qtdemo_rc
    C#使用RSA证书文件加密和解密示例
    VIM自动关闭预览提示窗口
    VMware和VirtualBox中的网络适配器类型及虚拟网络性能优化
    正则表达式Java
  • 原文地址:https://www.cnblogs.com/wynblogscc/p/15138423.html
Copyright © 2011-2022 走看看