异步多线程之入Task详解
Posted 菜鸟厚非
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了异步多线程之入Task详解相关的知识,希望对你有一定的参考价值。
上一篇:异步多线程之入ThreadPool
下一篇:异步多线程之Parallel,待更新
简介
1.0 时代的 Thread 提供了太多太底层功能,在 2.0 时代的 Threadpool 切去了一些无用与不可控的 API ,并提供了线程重用与线程数量限制的功能,3.0 时代的 Task 基于 Threadpool 又做了个补救,增加了多个实用的 API,满足了工作中使用场景。
启动多线程方式
Task 对于启动一个新的线程,提供的 API 还是比较丰富的 Run、New Task、Task Factory 都可以启动一个新的线程
Task.Run
例如:启用一个线程
public static void DoSomethingLong(string name)
Console.WriteLine($"name DoSomethingLong Start,ThreadId:Thread.CurrentThread.ManagedThreadId,Datetime:DateTime.Now.ToLongTimeString()");
Console.WriteLine($"name DoSomethingLong End,ThreadId:Thread.CurrentThread.ManagedThreadId,Datetime:DateTime.Now.ToLongTimeString()");
static void Main(string[] args)
Console.WriteLine($"Main Start,ThreadId:Thread.CurrentThread.ManagedThreadId,Datetime:DateTime.Now.ToLongTimeString()");
Task.Run(() => DoSomethingLong("张三"));
Console.WriteLine($"Main End,ThreadId:Thread.CurrentThread.ManagedThreadId,Datetime:DateTime.Now.ToLongTimeString()");
Console.ReadLine();
New Task
例如:启用一个线程
public static void DoSomethingLong(string name)
Console.WriteLine($"name DoSomethingLong Start,ThreadId:Thread.CurrentThread.ManagedThreadId,Datetime:DateTime.Now.ToLongTimeString()");
Console.WriteLine($"name DoSomethingLong End,ThreadId:Thread.CurrentThread.ManagedThreadId,Datetime:DateTime.Now.ToLongTimeString()");
static void Main(string[] args)
Console.WriteLine($"Main Start,ThreadId:Thread.CurrentThread.ManagedThreadId,Datetime:DateTime.Now.ToLongTimeString()");
new Task(() => DoSomethingLong("张三")).Start();
Console.WriteLine($"Main End,ThreadId:Thread.CurrentThread.ManagedThreadId,Datetime:DateTime.Now.ToLongTimeString()");
Console.ReadLine();
Task Factory
例如:启用一个线程
public static void DoSomethingLong(string name)
Console.WriteLine($"name DoSomethingLong Start,ThreadId:Thread.CurrentThread.ManagedThreadId,Datetime:DateTime.Now.ToLongTimeString()");
Console.WriteLine($"name DoSomethingLong End,ThreadId:Thread.CurrentThread.ManagedThreadId,Datetime:DateTime.Now.ToLongTimeString()");
static void Main(string[] args)
Console.WriteLine($"Main Start,ThreadId:Thread.CurrentThread.ManagedThreadId,Datetime:DateTime.Now.ToLongTimeString()");
TaskFactory taskFactory = Task.Factory;
taskFactory.StartNew(() => DoSomethingLong("张三"));
Console.WriteLine($"Main End,ThreadId:Thread.CurrentThread.ManagedThreadId,Datetime:DateTime.Now.ToLongTimeString()");
Console.ReadLine();
API、应用场景
什么时候可以用多线程?不要说什么提高效率、异步啊,这都是技术名词没有用的。首先任务可以并发执行,即多任务可以分开,满足了条件后用了并发后再说提升速度、异步啊。
我们以项目经理与开发者们,完成项目开发为例,进行讲解多线程(主线程想象成项目经理,子线程想象成开发人员)。
当项目开始的时候,项目经理需要启动一个项目,做一些准备工作,然后开发人员开始编程
例如:定义 Coding 方法,提给给开发者开项目模块使用,Main 为项目经理角色
public static void Coding(string name,string module)
Console.WriteLine($"name Coding Start module,ThreadId:Thread.CurrentThread.ManagedThreadId,Datetime:DateTime.Now.ToLongTimeString()");
Console.WriteLine($"name Coding End module,ThreadId:Thread.CurrentThread.ManagedThreadId,Datetime:DateTime.Now.ToLongTimeString()");
static void Main(string[] args)
Console.WriteLine($"项目经理启动一个项目,ThreadId:Thread.CurrentThread.ManagedThreadId,Datetime:DateTime.Now.ToLongTimeString()");
Console.WriteLine($"前置的准备工作,ThreadId:Thread.CurrentThread.ManagedThreadId,Datetime:DateTime.Now.ToLongTimeString()");
Console.WriteLine($"开始编程,ThreadId:Thread.CurrentThread.ManagedThreadId,Datetime:DateTime.Now.ToLongTimeString()");
Task.Run(() => Coding("张三","Web"));
Task.Run(() => Coding("李四", "Service"));
Task.Run(() => Coding("王五", "SQL"));
Console.ReadLine();
启动程序,项目经理(线程 1)做准备工作,开发者们(子线程 3、4、5)并发完成 Coding
WaitAll
例如:当项目开发完成,项目经理需要进行通知甲方验收对吧。所以我们在 Main 方法项目添加通知甲方验收
public static void Coding(string name,string module)
Console.WriteLine($"name Coding Start module,ThreadId:Thread.CurrentThread.ManagedThreadId,Datetime:DateTime.Now.ToLongTimeString()");
Console.WriteLine($"name Coding End module,ThreadId:Thread.CurrentThread.ManagedThreadId,Datetime:DateTime.Now.ToLongTimeString()");
static void Main(string[] args)
Console.WriteLine($"项目经理启动一个项目,ThreadId:Thread.CurrentThread.ManagedThreadId,Datetime:DateTime.Now.ToLongTimeString()");
Console.WriteLine($"前置的准备工作,ThreadId:Thread.CurrentThread.ManagedThreadId,Datetime:DateTime.Now.ToLongTimeString()");
Console.WriteLine($"开始编程,ThreadId:Thread.CurrentThread.ManagedThreadId,Datetime:DateTime.Now.ToLongTimeString()");
Task.Run(() => Coding("张三","Web"));
Task.Run(() => Coding("李四", "Service"));
Task.Run(() => Coding("王五", "SQL"));
Console.WriteLine($"通知甲方验收,ThreadId:Thread.CurrentThread.ManagedThreadId,Datetime:DateTime.Now.ToLongTimeString()");
Console.ReadLine();
启动程序,啥情况,开发人员没有 coding 完成,项目经理就通知,甲方验收了。所以,项目经理需要等待开发人员 coding 完成之后,再进行通知甲方验收。
接着我们对程序进行修改,Task 通过了线程等待的方法,不过是 Array 类型的。 我们定义 List 将 个个开发者的任务添加到集合中,使用 WaitAll 方法进行等待全部任务完成。
public static void Coding(string name, string module)
Console.WriteLine($"name Coding Start module,ThreadId:Thread.CurrentThread.ManagedThreadId,Datetime:DateTime.Now.ToLongTimeString()");
Console.WriteLine($"name Coding End module,ThreadId:Thread.CurrentThread.ManagedThreadId,Datetime:DateTime.Now.ToLongTimeString()");
static void Main(string[] args)
List<Task> tasks = new List<Task>();
Console.WriteLine($"项目经理启动一个项目,ThreadId:Thread.CurrentThread.ManagedThreadId,Datetime:DateTime.Now.ToLongTimeString()");
Console.WriteLine($"前置的准备工作,ThreadId:Thread.CurrentThread.ManagedThreadId,Datetime:DateTime.Now.ToLongTimeString()");
Console.WriteLine($"开始编程,ThreadId:Thread.CurrentThread.ManagedThreadId,Datetime:DateTime.Now.ToLongTimeString()");
tasks.Add(Task.Run(() => Coding("张三", "Web")));
tasks.Add(Task.Run(() => Coding("李四", "Service")));
tasks.Add(Task.Run(() => Coding("王五", "SQL")));
Task.WaitAll(tasks.ToArray()); // 会阻塞当前线程,所有任务完成后,才进入下一行 卡界面
Console.WriteLine($"通知甲方验收,ThreadId:Thread.CurrentThread.ManagedThreadId,Datetime:DateTime.Now.ToLongTimeString()");
Console.ReadLine();
启动程序,可以看到这次在开发者们(子线程 3、4、6)完成 Coding 后,项目经理(主线程 1)再通知甲方进行验收
WaitAll 等待也可以超时
WaitAny
例如:有时项目经理不知道开发项目的进度,于是在项目中任何一个模块开发完成后进行记录。Task提供了对应得 API WaitAny 方法,即任何一个子线程完成工作即开始下一行代码。
public static void Coding(string name, string module)
Console.WriteLine($"name Coding Start module,ThreadId:Thread.CurrentThread.ManagedThreadId,Datetime:DateTime.Now.ToLongTimeString()");
Console.WriteLine($"name Coding End module,ThreadId:Thread.CurrentThread.ManagedThreadId,Datetime:DateTime.Now.ToLongTimeString()");
static void Main(string[] args)
List<Task> tasks = new List<Task>();
Console.WriteLine($"项目经理启动一个项目,ThreadId:Thread.CurrentThread.ManagedThreadId,Datetime:DateTime.Now.ToLongTimeString()");
Console.WriteLine($"前置的准备工作,ThreadId:Thread.CurrentThread.ManagedThreadId,Datetime:DateTimeC#/.NET 多线程任务Task的详解——应用实例
异步和多线程,委托异步调用,Thread,ThreadPool,Task,Parallel,CancellationTokenSource