Async Await 多线程等待 应用
不同框架的应用
///1.Winform--存在特殊处理
///2.ASP.NETCore---放心用
///3.控制台---放心用
///4.WPF----没试过---
///5.Core WebApi---放心用
Web开发 推荐
适用
跟第三方交互的(非托管资源,经常有async版本): 数据库openAsync-Redis Web请求-Api 文件读取 一用到底 Await为什么能提升吞吐—只负责发命令—然后就忙别的去了—不需 要等待---事儿完成前就不浪费资源---完成后再来线程处理---这里还 能复用
不适用
服务器本地计算(CPU密集型,托管资源 ) : 大数据加减乘除, 数据处理 反而可能影响性能 但是用了没啥事儿
用法
1 async 是用来修饰方法,如果单独出现,方法会警告,没有什么作用
2 await在方法体内部,只能放在async修饰的方法内,必须放在task前面
3 async/await方法里面如果没有返回值,默认返回一个Task,或者void(推荐用Task,而不是void,因为这 样才能await/wait)
4 带async+await后,返回值要多一层Task<>
硬件DMA技术, 带Async后缀的API 硬盘:接受命令—然后cpu忙自己的(线程)—写完/读完,会发中断信 号,CPU再继续处理,这就基于DMA异步操作,就是可以节约CPU 资源(线程)---- 线程启动-等着-当然很浪费 用了异步就不用等

4种等待方式
t.Wait()
Task.WaitAll()
t.Result
await t
Winform
/// <summary>
///异步方法: 正常执行
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private async void btnAsync_Click(object sender, EventArgs e)
{
Debug.WriteLine($"**********************************btnAsync_Click******************************************");
Debug.WriteLine($"This is btnAsync_Click Start,ThreadId={Thread.CurrentThread.ManagedThreadId}");
long lResult = await this.CalculationAsync(1_000_000);
Debug.WriteLine($"This is btnAsync_Click End,ThreadId={Thread.CurrentThread.ManagedThreadId}");
this.textAsyncResult.Text = lResult.ToString(); //这句话必须要主线程来执行的
//更改控件的值,这里必须是(UI线程)主线程去执行;每次执行都能成功,说明每次这里都是主线程来执行的;跟Winform设计有关系;在Winform中,await后面的内容,都会让主线程来执行;
}
private async Task<long> CalculationAsync(long total)
{
var task = await Task.Run(() =>
{
Debug.WriteLine($"This is CalculationAsync Start,ThreadId={Thread.CurrentThread.ManagedThreadId}");
long lResult = 0;
for (int i = 0; i < total; i++)
{
lResult += i;
}
Debug.WriteLine($"This is CalculationAsync End,ThreadId={Thread.CurrentThread.ManagedThreadId}");
return lResult;
});
return task; //这句话必须由主线程来执行,线程在同一时刻只能做一件事儿
}
/// <summary>
/// 同步方法:界面卡死了 新加一个线程变成三个线程等待 就不会死锁了
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnSync_Click(object sender, EventArgs e)
{
Debug.WriteLine($"**********************************btnSync_Click******************************************");
Debug.WriteLine($"This is btnSync_Click Start,ThreadId={Thread.CurrentThread.ManagedThreadId}");
//var task = this.CalculationAsync(1_000_000);
////task.Wait(); //主线程阻塞等待
////1.主线程要等待 Winform特殊设计:await后面的内容必须由主线程执行;
////2.主线程在这儿也等待着在
////3.主线程无暇分身导致死锁
////4.怎么解决这个死锁?
//long lResult = task.Result;//主线程阻塞等待,主线程在等结果,经过分析可以确定,界面卡死问题肯定是出在这儿
long lResult = this.GetCalculationAsync(1_000_000);
Debug.WriteLine($"This is btnSync_Click End,ThreadId={Thread.CurrentThread.ManagedThreadId}");
this.textSync.Text = lResult.ToString();
}
private long GetCalculationAsync(long total)
{
var taskLong = Task.Run(() =>
{ //新开一个线程
var task = this.CalculationAsync(total);
long lResult = task.Result;//子线程
return lResult;
});
return taskLong.Result;//主线程在等Result
}
private void btnSync_Click(object sender, EventArgs e)
{
Debug.WriteLine($"**********************************btnSync_Click******************************************");
Debug.WriteLine($"This is btnSync_Click Start,ThreadId={Thread.CurrentThread.ManagedThreadId}");
var task = this.CalculationAsync(1_000_000);
//task.Wait(); //主线程阻塞等待
////1.主线程要等待 Winform特殊设计:await后面的内容必须由主线程执行;
////2.主线程在这儿也等待着在
////3.主线程无暇分身导致死锁
////4.怎么解决这个死锁?
long lResult = task.Result;//主线程阻塞等待,主线程在等结果,经过分析可以确定,界面卡死问题肯定是出在这儿 ------等待---相互等待锁死
// long lResult = this.GetCalculationAsync(1_000_000); windform 中await后面必须由主线程完成
Debug.WriteLine($"This is btnSync_Click End,ThreadId={Thread.CurrentThread.ManagedThreadId}");
this.textSync.Text = lResult.ToString();
}
private async Task<long> CalculationAsync(long total)
{
var task = await Task.Run(() =>
{
Debug.WriteLine($"This is CalculationAsync Start,ThreadId={Thread.CurrentThread.ManagedThreadId}");
long lResult = 0;
for (int i = 0; i < total; i++)
{
lResult += i;
}
Debug.WriteLine($"This is CalculationAsync End,ThreadId={Thread.CurrentThread.ManagedThreadId}");
return lResult;
});
return task; //这句话必须由主线程来执行,线程在同一时刻只能做一件事儿 -----(主线程在等待)----
}
测试用例
public class AwaitAsyncTest
{
public static void Show()
{
#region ReadFile //ReadFile对比Task:当然并发---10个线程 Async: 可以并发,但是并发不多---只有3个线程 Sync:同步,按顺序执行
{
Console.WriteLine("******************ReadFile***************");
string path = "D:\\ZXWork\\Advanced15\\20210713Advanced15Course05Delegate.rar";
int loopNum = 20;
{
Console.WriteLine("*****************Async****************");
List<Task> taskList = new List<Task>();
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
for (int i = 0; i < loopNum; i++)
{
taskList.Add(ReadAsync(path, i));
}
Task.WaitAll(taskList.ToArray());
stopwatch.Stop();
Console.WriteLine($"Async耗时{stopwatch.ElapsedMilliseconds}ms,ThreadId={Thread.CurrentThread.ManagedThreadId}");
}
Thread.Sleep(3000);
{
Console.WriteLine("*****************Task****************");
List<Task> taskList = new List<Task>();
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
for (int i = 0; i < loopNum; i++)
{
taskList.Add(ReadTask(path, i));
}
Task.WaitAll(taskList.ToArray());
stopwatch.Stop();
Console.WriteLine($"Task耗时{stopwatch.ElapsedMilliseconds}ms,ThreadId={Thread.CurrentThread.ManagedThreadId}");
}
Thread.Sleep(3000);
//{
// Console.WriteLine("*****************Sync****************");
// Stopwatch stopwatch = new Stopwatch();
// stopwatch.Start();
// for (int i = 0; i < loopNum; i++)
// {
// ReadSync(path, i);
// }
// stopwatch.Stop();
// Console.WriteLine($"Sync耗时{stopwatch.ElapsedMilliseconds}ms,ThreadId={Thread.CurrentThread.ManagedThreadId}");
//}
}
#endregion
#region InvokeWeb //InvokeWeb对比 Task:耗时长一些,并发不够高------10个线程---铁打的10个线程 Async:并发高,速度快----少于10个线程,没有影响并发,能重用就是没事儿了, 利用率高一些 Sync:串行的,耗时长
{
Console.WriteLine("******************InvokeWeb***************");
string url = "http://localhost:8080/home/Sleep";
int loopNum = 10;//5
int second = 5;
{
Console.WriteLine("*****************Async****************");
List<Task> taskList = new List<Task>();
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
for (int i = 0; i < loopNum; i++)
{
taskList.Add(WebAsync(url, i, second));
}
Task.WaitAll(taskList.ToArray());
stopwatch.Stop();
Console.WriteLine($"Async耗时{stopwatch.ElapsedMilliseconds}ms,ThreadId={Thread.CurrentThread.ManagedThreadId}");
}
Thread.Sleep(3000);
{
Console.WriteLine("*****************Task****************");
List<Task> taskList = new List<Task>();
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
for (int i = 0; i < loopNum; i++)
{
taskList.Add(WebTask(url, i, second));
}
Task.WaitAll(taskList.ToArray());
stopwatch.Stop();
Console.WriteLine($"Task耗时{stopwatch.ElapsedMilliseconds}ms,ThreadId={Thread.CurrentThread.ManagedThreadId}");
}
Thread.Sleep(3000);
{
Console.WriteLine("*****************Sync****************");
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
for (int i = 0; i < loopNum; i++)
{
WebSync(url, i, second);
}
stopwatch.Stop();
Console.WriteLine($"Sync耗时{stopwatch.ElapsedMilliseconds}ms,ThreadId={Thread.CurrentThread.ManagedThreadId}");
}
}
#endregion
#region DoCalculation
{
Console.WriteLine("******************DoCalculation***************");
int loopNum = 10;//5
long total = 1_000_000_000;
{
Console.WriteLine("*****************Task****************");
List<Task> taskList = new List<Task>();
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
for (int i = 0; i < loopNum; i++)
{
taskList.Add(DoCalculationTask(total, i));
}
Task.WaitAll(taskList.ToArray());
stopwatch.Stop();
Console.WriteLine($"Task耗时{stopwatch.ElapsedMilliseconds}ms,ThreadId={Thread.CurrentThread.ManagedThreadId}");
}
Thread.Sleep(3000);
{
Console.WriteLine("*****************Async****************");
List<Task> taskList = new List<Task>();
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
for (int i = 0; i < loopNum; i++)
{
taskList.Add(DoCalculationAsync(total, i));
}
Task.WaitAll(taskList.ToArray());
stopwatch.Stop();
Console.WriteLine($"Async耗时{stopwatch.ElapsedMilliseconds}ms,ThreadId={Thread.CurrentThread.ManagedThreadId}");
}
Thread.Sleep(3000);
{
Console.WriteLine("*****************Sync****************");
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
for (int i = 0; i < loopNum; i++)
{
DoCalculationSync(total, i);
}
stopwatch.Stop();
Console.WriteLine($"Sync耗时{stopwatch.ElapsedMilliseconds}ms,ThreadId={Thread.CurrentThread.ManagedThreadId}");
}
}
#endregion
}
#region Read
//await后面也会开启线程---只要其中一个执行结束了,当前这个现场马上可能去执行其他的人
private static async Task<byte[]> ReadAsync(string path, int num)
{
Console.WriteLine($"This is ReadAsync{num} Start,ThreadId={Thread.CurrentThread.ManagedThreadId}");
var result = await File.ReadAllBytesAsync(path);
//这里读取文件:文件--比较大,也是耗好性能--计算机肯定回卡,主线程到这儿相当于说是告诉帮助类库,要做什么事儿,主线程就跑了,在这类并没有开启新的线程---降低了线程的开启的数量; 也降低了CPU的负荷; 降低了服务器的运行负荷
Console.WriteLine($"This is ReadAsync{num} End,ThreadId={Thread.CurrentThread.ManagedThreadId}");
return result;
}
//铁定10个线程
private static Task<byte[]> ReadTask(string path, int num)
{
Console.WriteLine($"This is ReadTask{num} Start,ThreadId={Thread.CurrentThread.ManagedThreadId}");
var result = Task.Run(() =>
{
Console.WriteLine($"This is ReadTask Ing,ThreadId={Thread.CurrentThread.ManagedThreadId}");
return File.ReadAllBytes(path);
});
Console.WriteLine($"This is ReadTask{num} End,ThreadId={Thread.CurrentThread.ManagedThreadId}");
return result;
}
private static byte[] ReadSync(string path, int num)
{
Console.WriteLine($"This is ReadSync{num} Start,ThreadId={Thread.CurrentThread.ManagedThreadId}");
var result = File.ReadAllBytes(path);
Console.WriteLine($"This is ReadSync{num} End,ThreadId={Thread.CurrentThread.ManagedThreadId}");
return result;
}
#endregion
#region InvokeWebRequest
private static string InvokeWebRequest(string url)
{
string html = null;
try
{
HttpWebRequest request = HttpWebRequest.Create(url) as HttpWebRequest;//模拟请求
request.Timeout = 30 * 1000;//
using (HttpWebResponse response = request.GetResponse() as HttpWebResponse)//发起请求
{
if (response.StatusCode != HttpStatusCode.OK)
{
Console.WriteLine($"抓取{url}地址返回失败,response.StatusCode为{response.StatusCode}");
}
else
{
StreamReader sr = new StreamReader(response.GetResponseStream());
html = sr.ReadToEnd();//读取数据
}
}
}
catch (WebException ex)
{
if (ex.Message.Equals("远程服务器返回错误: (306)。"))
{
Console.WriteLine($"抓取{url}地址返回失败,远程服务器返回错误: (306)");
html = null;
}
}
catch (Exception ex)
{
Console.WriteLine($"抓取{url}地址返回失败,远程服务器返回错误{ex.Message}");
html = null;
}
return html;
}
private static async Task<string> InvokeWebRequestAsync(string url)
{
string html = null;
try
{
HttpWebRequest request = HttpWebRequest.Create(url) as HttpWebRequest;//模拟请求
request.Timeout = 30 * 1000;// //request.GetResponseAsync异步版本的发起请求
using (HttpWebResponse response = (await request.GetResponseAsync()) as HttpWebResponse)//发起请求
{
if (response.StatusCode != HttpStatusCode.OK)
{
Console.WriteLine($"抓取{url}地址返回失败,response.StatusCode为{response.StatusCode}");
}
else
{
StreamReader sr = new StreamReader(response.GetResponseStream());
return await sr.ReadToEndAsync();//异步
}
}
}
catch (WebException ex)
{
if (ex.Message.Equals("远程服务器返回错误: (306)。"))
{
Console.WriteLine($"抓取{url}地址返回失败,远程服务器返回错误: (306)");
html = null;
}
}
catch (Exception ex)
{
Console.WriteLine($"抓取{url}地址返回失败,远程服务器返回错误{ex.Message}");
html = null;
}
return html;
}
private static async Task<string> WebAsync(string url, int num, int second)
{
url = $"{url}?loop={num}&type=Async&second={second}";
Console.WriteLine($"This is InvokeAsync{url} Start,ThreadId={Thread.CurrentThread.ManagedThreadId}");
var result = await InvokeWebRequestAsync(url);
Console.WriteLine($"This is InvokeAsync{url} End,ThreadId={Thread.CurrentThread.ManagedThreadId}");
return result;
}
private static Task<string> WebTask(string url, int num, int second)
{
url = $"{url}?loop={num}&type=Task&second={second}";
Console.WriteLine($"This is WebTask{num} Start,ThreadId={Thread.CurrentThread.ManagedThreadId}");
var result = Task.Run(() =>
{
Console.WriteLine($"This is WebTask Ing,ThreadId={Thread.CurrentThread.ManagedThreadId}");
return InvokeWebRequest(url);
});
Console.WriteLine($"This is WebTask{num} End,ThreadId={Thread.CurrentThread.ManagedThreadId}");
return result;
}
private static string WebSync(string url, int num, int second)
{
url = $"{url}?loop={num}&type=Sync&second={second}";
Console.WriteLine($"This is WebSync{num} Start,ThreadId={Thread.CurrentThread.ManagedThreadId}");
var result = InvokeWebRequest(url);
Console.WriteLine($"This is WebSync{num} End,ThreadId={Thread.CurrentThread.ManagedThreadId}");
return result;
}
#endregion
#region DoCalculation CPU密集型
private static long Calculation(long total)
{
long lResult = 0;
for (int i = 0; i < total; i++)
{
lResult += i;
}
return lResult;
}
private static async Task<long> CalculationAsync(long total)
{
return await Task.Run(() =>
{
long lResult = 0;
for (int i = 0; i < total; i++)
{
lResult += i;
}
return lResult;
});
}
private static async Task<long> DoCalculationAsync(long total, int num)
{
Console.WriteLine($"This is DoCalculationAsync{num} Start,ThreadId={Thread.CurrentThread.ManagedThreadId}");
var result = await CalculationAsync(total);
Console.WriteLine($"This is DoCalculationAsync{num} End,ThreadId={Thread.CurrentThread.ManagedThreadId}");
return result;
}
private static Task<long> DoCalculationTask(long total, int num)
{
Console.WriteLine($"This is DoCalculationTask{num} Start,ThreadId={Thread.CurrentThread.ManagedThreadId}");
var result = Task.Run(() =>
{
Console.WriteLine($"This is DoCalculationTask Ing,ThreadId={Thread.CurrentThread.ManagedThreadId}");
return Calculation(total);
});
Console.WriteLine($"This is DoCalculationTask{num} End,ThreadId={Thread.CurrentThread.ManagedThreadId}");
return result;
}
private static long DoCalculationSync(long total, int num)
{
Console.WriteLine($"This is DoCalculationSync{num} Start,ThreadId={Thread.CurrentThread.ManagedThreadId}");
var result = Calculation(total);
Console.WriteLine($"This is DoCalculationSync{num} End,ThreadId={Thread.CurrentThread.ManagedThreadId}");
return result;
}
#endregion
}
浙公网安备 33010602011771号