Async和Await关键字
文章目录
- 前言
- 一、基本概念
- 二、使用步骤
前言
Async和Await关键字!
一、基本概念
async 关键字
基本概念 :async 修饰符用于指定方法是异步执行的,它告诉编译器该方法中可能包含一个或多个 await 表达式。被 async 修饰的方法称为异步方法,它会返回一个任务对象(Task 或 Task<TResult>
),该任务对象表示异步操作。
语法 :在方法声明中使用 async 修饰符,位于访问修饰符之后,返回类型之前。例如:
async Task MyAsyncMethod()
async Task<int>
MyAsyncMethod()
await 关键字
基本概念 :await 运算符用于等待异步操作完成。它会暂停当前方法的执行,直到等待的异步操作完成,然后将控制权交回给调用者。await 操作符通常用于等待 Task 或 Task<TResult>
对象。
语法 :在表达式前面使用 await 关键字,通常用于等待异步方法返回的 Task 或 Task。例如:
await MyAsyncMethod();
int result = await MyAsyncMethod();
二、使用步骤
首看一下效果
同步效果,当执行比较耗时的IO时,主线程会被阻塞在比较耗时的IO处,得等到IO结束才能执行后面的代码,所以当还在下载内容时,窗体拖不动,得等到IO结束后才能拖动。
private void btnSyncDownload_Click(object sender, EventArgs e)
{txtResult.Text = "";var stopwatch = Stopwatch.StartNew();DownloadWebSietSycn();txtResult.Text += $"Elapsed time: {stopwatch.Elapsed}{Environment.NewLine}";
}private void DownloadWebSietSycn()
{foreach (var site in Contents.WebSites){var result = DownloadWebSitSync(site);ReportResult(result);}
}private void ReportResult(string result)
{txtResult.Text += result;
}private string DownloadWebSitSync(string url)
{var response = client.GetAsync(url).GetAwaiter().GetResult();var responsePayloadBytes = response.Content.ReadAsByteArrayAsync().GetAwaiter().GetResult();return $"Finish downloding data from {url}. Total bytes returned {responsePayloadBytes.Length}. {Environment.NewLine}";
}
使用Async和Await关键字就是告诉主线程,这个任务是交给其他线程处理,你可以继续去执行其他任务。代码解析:var result = await Task.Run(() => DownloadWebSitSync(site));表示需要等待这个线程执行完成并使用result 来接收返回值。
private async Task btnAsyncDownload_Click(object sender, EventArgs e)
{txtResult.Text = "";var stopwatch = Stopwatch.StartNew();DownloadWebSietAsycn();txtResult.Text += $"Elapsed time: {stopwatch.Elapsed}{Environment.NewLine}";
}private async Task DownloadWebSietAsycn()
{foreach (var site in Contents.WebSites){var result = await Task.Run(() => DownloadWebSitSync(site));ReportResult(result);}
}
注意:对于async 和await方法的返回值必须得是Task或者Task
仔细看,这个耗时在第一行就打印出来了并且用时非常短。
为了能在执行完DownloadWebSietAsycn()后执行这段txtResult.Text += $“Elapsed time: {stopwatch.Elapsed}{Environment.NewLine}”;代码,可以加上await关键字。
private async Task btnAsyncDownload_Click(object sender, EventArgs e)
{txtResult.Text = "";var stopwatch = Stopwatch.StartNew();await DownloadWebSietAsycn();txtResult.Text += $"Elapsed time: {stopwatch.Elapsed}{Environment.NewLine}";
}private async Task DownloadWebSietAsycn()
{foreach (var site in Contents.WebSites){var result = await Task.Run(() => DownloadWebSitSync(site));ReportResult(result);}
}
效果图
可以看出加了await关键字后这段代码txtResult.Text += $“Elapsed time: {stopwatch.Elapsed}{Environment.NewLine}”;会等DownloadWebSietAsycn()执行完才执行。
第一段代码
private async Task btnAsyncDownload_Click(object sender, EventArgs e)
{txtResult.Text = "";var stopwatch = Stopwatch.StartNew();DownloadWebSietAsycn();txtResult.Text += $"Elapsed time: {stopwatch.Elapsed}{Environment.NewLine}";
}
未使用 await 等待异步操作 :当调用 DownloadWebSietAsycn() 时,程序不会等待它完成,而是直接继续执行后续代码。
可能导致操作顺序问题 :这意味着在 DownloadWebSietAsycn 方法完成之前,可能会执行 txtResult.Text += … 这一行代码。这可能导致以下问题:
显示不完整的异步操作结果 :如果 DownloadWebSietAsycn 方法的任务还未完成,那么在这行代码执行时,txtResult 中可能不会显示完整的异步操作结果。
显示较长的经过时间 :即使 DownloadWebSietAsycn 方法的时间非常短,但由于 txtResult.Text += … 这行代码会立即执行,显示的经过时间可能会比实际时间长,因为它没有等待异步操作完成。
第二段代码
private async Task btnAsyncDownload_Click(object sender, EventArgs e)
{txtResult.Text = "";var stopwatch = Stopwatch.StartNew();await DownloadWebSietAsycn();txtResult.Text += $"Elapsed time: {stopwatch.Elapsed}{Environment.NewLine}";
}
使用 await 等待异步操作 :当调用 await DownloadWebSietAsycn() 时,程序会暂停当前方法的执行,等待 DownloadWebSietAsycn 方法完成后再继续执行后续代码。
确保操作顺序 :这意味着在 DownloadWebSietAsycn 方法完成之前,不会执行 txtResult.Text += … 这一行代码。因此,你可以确保在 DownloadWebSietAsycn 方法完成后,才去获取和显示经过时间。
性能和响应能力 :在等待 DownloadWebSietAsycn 方法完成时,线程不会被阻塞,这样可以提高程序的性能和响应能力,改善用户体验。
在 await DownloadWebSietAsycn() 中,程序的其他任务不会等待 DownloadWebSietAsycn() 执行完成 ,只有当前的异步方法(这里是 btnAsyncDownload_Click)会在这个 await 表达式处暂停执行,等待 DownloadWebSietAsycn() 完成。
当前异步方法的暂停
在遇到 await DownloadWebSietAsycn() 时,btnAsyncDownload_Click 方法会把控制权交还给调用者(通常是 UI 消息循环)。它会在 DownloadWebSietAsycn() 返回的结果(因为 DownloadWebSietAsycn() 是异步方法,返回的是一个 Task)完成后,继续执行后续代码。
这是异步编程的一个关键特性,它允许方法在等待异步操作完成时,不阻塞整个线程。这样可以使应用程序的 UI 保持响应,因为 UI 线程没有被长时间占用。
其他任务的执行
如果程序中有其他独立的任务,它们不会因为 DownloadWebSietAsycn() 的执行而被阻塞。例如,如果有其他按钮点击事件处理程序或者其他后台线程任务,它们可以继续执行。
这是因为现代操作系统和编程环境(如 C# 的多线程和异步编程模型)允许多个任务并行运行。在 C# 中,异步方法通常是基于任务(Task - based)的异步模式,这些任务可以在后台线程池中执行,或者以其他非阻塞的方式运行。