1.1 基本介绍
Task被称为多线程的最佳实践,
(1)Task线程全是线程池线程
(2)提供了丰富的API ,非常适合实践
1.2 创建和执行Task
Task 可以通过多种方式创建实例。 从 .NET Framework 4.5 开始,最常见的方法是调用静态Run方法。 此方法 Run 提供了一种使用默认值启动任务的简单方法,
而无需其他参数。
public static async Task Main() { await Task.Run(() => { // Just loop. int ctr = 0; for (ctr = 0; ctr <= 1000000; ctr++) { } Console.WriteLine("Finished {0} loop iterations", ctr); }); }
一种替代方法,也是在 .NET Framework 4 中启动任务的最常见方法是静态TaskFactory.StartNew方法。 该 Task.Factory 属性返回对象 TaskFactory 。 使用此方法的 TaskFactory.StartNew 重载可以指定参数以传递给任务创建选项和任务计划程序。
public static void Main() { Task t = Task.Factory.StartNew( () => { // Just loop. int ctr = 0; for (ctr = 0; ctr <= 1000000; ctr++) {} Console.WriteLine("Finished {0} loop iterations", ctr); } ); t.Wait(); }
1.3 等待一个或多个任务完成
由于任务通常在线程池线程上异步运行,因此在实例化任务后,创建和启动任务的线程会继续执行。 在某些情况下,当调用线程是主应用程序线程时,应用可能会在任务实际开始执行之前终止。 其他情况下,应用程序的逻辑可能要求调用线程仅在一个或多个任务完成执行时才继续执行。 可以通过调用 Wait 方法等待一个或多个任务完成来同步调用线程的执行及其启动的异步任务。
若要等待单个任务完成,可以调用其 Task.Wait 方法。 对方法的 Wait 调用会阻止调用线程,直到单个类实例完成执行。
static void Main(string[] args) { Task task1 = Task.Run(()=>Thread.Sleep(3000)); Console.WriteLine($"task1状态:{task1.Status}"); try { task1.Wait(); Console.WriteLine($"task1状态:{task1.Status}"); Console.WriteLine("我是主线程"); } catch (AggregateException ex) { Console.WriteLine($"task1发生异常,{ex.Message}"); } Console.ReadLine(); }
在某些情况下,你可能希望等待一系列执行任务中的第一个完成,但不关心它所在的任务。 为此,可以调用方法的 Task.WaitAny 重载之一。
static void Main(string[] args) { var tasks = new Task[3]; var random = new Random(); for (int i = 0; i < 3; i++) { tasks[i] = Task.Run(()=>Thread.Sleep(random.Next(500,3000))); } try { int index = Task.WaitAny(tasks); Console.WriteLine($"任务{tasks[index].Id} 第一个完成.\n"); Console.WriteLine("所有任务状态:"); foreach (var t in tasks) { Console.WriteLine($"任务{t.Id}:{t.Status}"); } } catch (AggregateException ex) { Console.WriteLine($"发生异常,{ex.Message}"); } Console.ReadLine(); }
还可以通过调用 WaitAll 方法等待所有一系列任务完成。 以下示例创建 10 个任务,等待所有 10 个任务完成,然后显示其状态。
public static void Main() { Task[] tasks = new Task[10]; for (int i = 0; i < 10; i++) { tasks[i] = Task.Run(() => Thread.Sleep(2000)); } try { Task.WaitAll(tasks); } catch (AggregateException ex) { Console.WriteLine("发生异常: "); foreach (var innerex in ex.Flatten().InnerExceptions) Console.WriteLine(" {0}", innerex.Message); } Console.WriteLine("Status of completed tasks:"); foreach (var t in tasks) Console.WriteLine(" 任务{0}: {1}", t.Id, t.Status); }
经常使用的四个方法:
Task.WaitAny(tasks);
Task.WaitAll(tasks);
Task.WhenAny(tasks);
Task.WhenAll(tasks);
1.4 回调
static void Main(string[] args) { var task1 = Task.Run(()=> { Thread.Sleep(1000); Console.WriteLine("task1 tid={0}, dt={1}", Thread.CurrentThread.ManagedThreadId, DateTime.Now); }); var task2= task1.ContinueWith(t=> { Console.WriteLine("task2 tid={0}, dt={1}", Thread.CurrentThread.ManagedThreadId, DateTime.Now); }); var task3 = task2.ContinueWith(t => { Console.WriteLine("task3 tid={0}, dt={1}", Thread.CurrentThread.ManagedThreadId, DateTime.Now); }); Console.ReadKey(); }
1.5 所有方法
参考:https://docs.microsoft.com/zh-cn/dotnet/api/system.threading.tasks?view=netframework-4.8