.NET 多线程 Task async await
多线程概念
两个名词
线程不安全:多个线程访问同一段代码,产生不确定结果(冲突)
线程安全:各个线程正常且正确执行,不会出现数据污染等意外
多线程的例子
例1:两个线程同时打印
static void Main(string[] args) { Method1(); Method2(); Console.WriteLine(" main end "); Console.ReadKey(); } public static async Task Method1() { await Task.Run(() => { for (int i = 0; i < 50; i++) { Task.Delay(500).Wait(); Console.WriteLine(" Method 1"); } }); } public static void Method2() { for (int i = 0; i < 20; i++) { Task.Delay(1000).Wait(); Console.WriteLine(" Method 2"); } }
输出
例子2:存在依赖支线线程的主线程
Method3 需要一个从 Method1 返回来的 int 数,用 await 等待返回的结果。
static void Main(string[] args) { callMethod(); Console.ReadKey(); } public static async void callMethod() { Task<int> task = Method1(); Method2(); int count = await task; //或者写 task.Result; //主线程会停在这一步 Console.WriteLine("call end"); Method3(count); } public static async Task<int> Method1() { int count = 0; await Task.Run(() => { for (int i = 0; i < 50; i++) { Task.Delay(100).Wait(); Console.WriteLine(" Method 1"); count += 1; } }); return count; } public static void Method2() { for (int i = 0; i < 20; i++) { Task.Delay(200).Wait(); Console.WriteLine(" Method 2"); } } public static void Method3(int count) { Console.WriteLine("Total count is " + count); }
输出
Task相关
Task 开启一个新任务
开启后台线程:Task.Run() 或者 Task.Factory.StartNew()
以 Task.Run() 开启一个新任务
//返回值类型为string Task<string> task = Task<string>.Run(() => { Thread.Sleep(2000); //或 Task.Delay(2000).Wait(); return Thread.CurrentThread.ManagedThreadId.ToString(); }); //会等到task执行完毕才会输出; Console.WriteLine(task.Result); //task.Result 可改成 await task
Task.Factory.StartNew() 可以使用比 Task.Run() 更多的参数,可以做更多定制(如长时间运行)。 参考传送门
Task.Factory.StartNew(() => { Console.WriteLine("进行 线程" + Thread.CurrentThread.ManagedThreadId); }, TaskCreationOptions.LongRunning); //设置线程是长时间运行的,这时线程池就不会等待这个线程回收
注:Task 任务可以通过 CancellationTokenSource 类来取消。
Task.Wait() 和 await Task
Task.Wait() 阻塞线程,等待期间,系统不会对其他操作响应
await Task 等待任务完成,等待期间,系统可以响应其他操作
Task.Delay() 和 Thread.Sleep()
1、Thread.Sleep 是同步延迟,Task.Delay异步延迟。
2、Thread.Sleep 会阻塞线程,Task.Delay不会。
3、Thread.Sleep不能取消,Task.Delay可以。
4. Task.Delay() 比 Thread.Sleep() 消耗更多的资源,但是Task.Delay()可用于为方法返回Task类型;或者根据CancellationToken取消标记动态取消等待
5. Task.Delay() 实质创建一个运行给定时间的任务, Thread.Sleep() 使当前线程休眠给定时间。
有条件的 Task
Task 内部提供多种多样的基于队列的链式任务管理方法,通过使用这些快捷方式,可以让异步队列有序的执行,比如 ContinueWith(),ContinueWhenAll(),ContinueWhenAny(),WaitAll(),WaitAny(),WhenAll(),WhenAny()
Task.WaitAll(t1, t2) 等待多个线程
Task.WaitAny(t1, t2) 等待任意一个线程
Task.WhenAll(t1, t2) 创建一个任务,任务会在集合中的所有 Task 对象都完成时完成(不会主动等待)
var tasks = new List<Task>();
tasks.Add(Task.Run( () => { Task.Delay(1000).Wait(); Console.WriteLine("1"); } ));
tasks.Add(Task.Run( () => { Task.Delay(2000).Wait(); Console.WriteLine("2"); } ));
Task t = Task.WhenAll(tasks);
t.Wait();
Console.WriteLine("3");
这里的输出顺序为:
1 2 3
Task.WhenAny(t1, t2) 任一任务完成时,创建将完成的任务(返回第一项完成的任务)。
var tasks = new List<Task>();
tasks.Add(Task.Run( () => { Task.Delay(1000).Wait(); Console.WriteLine("1"); } ));
tasks.Add(Task.Run( () => { Task.Delay(2000).Wait(); Console.WriteLine("2"); } ));
Task t = Task.WhenAny(tasks);
t.Wait();
Console.WriteLine("3");
这里的输出顺序为:
1 3 2
async 和 await 异步编程
1、凡是使用 await 关键字的方法,都必须打上 async 标记
2、async 标识方法内有异步方法,调用 async 方法,会立刻另起线程执行
3、await 只是显示等待线程结束:await 表示等待异步方法执行完,并取返回值
参考来源
https://www.cnblogs.com/doforfuture/p/6293926.html (Mr靖 的 C#中 Thread,Task,Async/Await,IAsyncResult 的那些事儿!)
https://www.cnblogs.com/zhao123/p/9999607.html (凌风95 的 C# Task.Run 和 Task.Factory.StartNew 区别)
https://www.cnblogs.com/yy1234/p/8073732.html (禅道 的 Task.Delay() 和 Thread.Sleep() 区别)
https://www.cnblogs.com/ma8023/p/11677394.html (逆骨苍狼 的 C# 中的Async 和 Await 的用法详解)
https://www.cnblogs.com/wangwust/p/9474786.html (wangwust 的 【.NET】- async await 异步编程)
https://www.cnblogs.com/viter/p/10201228.html (Ron Liang 的 Asp.Net Core 轻松学-多线程之Task快速上手)