一.通过指定Url下载数据(I/O 绑定)
通常我们是调用别人的异步方法,然后封装起来再用。
下面写一个异步方法
static async Task Main(string[] args)
{
await DownloadHtmlAsync("https://www.youzack.com", @"E:\a\1.txt");
Console.WriteLine("ok");
}
static async Task DownloadHtmlAsync(string url,string filename)
{
using (HttpClient httpClient = new HttpClient())
{
string html = await httpClient.GetStringAsync(url);
await File.WriteAllTextAsync(filename, html);
}
}
提取出一个英语学习网站html 下载到对应的文件中
结果为
运行成功
注意:
调用第三方类库的时候
如果同样的功能,既有同步方法,又有异步方法,那么首先使用异步方法。.NET5中 很多框架中的方法也都支持异步: Main、winForm事件处理函数。
对于不支持的异步方法怎么办? wait() (无返回值); Result (有返回值)。风险: 死锁。
尽量不用。
二.从网站Url获取返回的内容
private readonly HttpClient _httpClient = new HttpClient();
[HttpGet, Route("GetContent")]
public async Task<int> GetContent()
{
//挂起GetContent()来允许调用者(web服务器)
//接收另一个请求,而不是阻塞这个请求。
var result = await _httpClient.GetStringAsync("https://dotnetfoundation.org");
return result;
}
使用WinForm通过点击按钮使用HttpClient
异步请求获取内容:
例如,
private readonly HttpClient _httpClient = new HttpClient();
private async void OnGetContentButtonClick(object sender, RoutedEventArgs e)
{
// //捕获任务句柄,以便稍后等待后台任务。
var getContentFoundationHtmlTask = _httpClient.GetStringAsync("https://dotnetfoundation.org");
// UI线程上的任何其他工作都可以在这里完成,例如启用一个进度条。
//这是很重要的,在"await"调用之前,以便用户
//在执行此方法之前查看进度条。
NetworkProgressBar.IsEnabled = true;
NetworkProgressBar.Visibility = Visibility.Visible;
//等待操作符挂起OnGetContentButtonClick(),将控制返回给调用者。
//这是什么允许应用程序响应,而不是阻塞UI线程。
var result = await GetContentFoundationHtmlTask;
DotNetCountLabel.Text = result;
NetworkProgressBar.IsEnabled = false;
NetworkProgressBar.Visibility = Visibility.Collapsed;
}
三、API异步方法以及async和await关键字
.NET Framework 4.5 或更高版本以及 .NET Core 包含许多可与 async
和 await
结合使用的成员。 可以通过追加到成员名称的“Async”
后缀和 Task
或 Task<TResult>
的返回类型,识别这些成员。 例如,System.IO.Stream
类包含 CopyToAsync
、ReadAsync
和 WriteAsync
等方法,以及同步方法 CopyTo
、Read
和 Write
。
异步方法旨在成为非阻止操作。 异步方法中的 await
表达式在等待的任务正在运行时不会阻止当前线程。 相反,表达式在继续时注册方法的其余部分并将控件返回到异步方法的调用方。async
和 await
关键字不会创建其他线程。 因为异步方法不会在其自身线程上运行,因此它不需要多线程。
只有当方法处于活动状态时,该方法将在当前同步上下文中运行并使用线程上的时间。 可以使用 Task.Run 将占用大量 CPU 的工作移到后台线程,但是后台线程不会帮助正在等待结果的进程变为可用状态。
async 和 await的作用:
1)标记的异步方法可以使用 await
来指定暂停点。 await
运算符通知编译器异步方法:在等待的异步过程完成后才能继续通过该点。 同时,控制返回至异步方法的调用方。 异步方法在 await 表达式执行时暂停并不构成方法退出,只会导致 finally
代码块不运行。
2)标记的异步方法本身可以通过调用它的方法等待。
异步方法通常包含 await
运算符的一个或多个实例,但缺少 await
表达式也不会导致生成编译器错误。 如果异步方法未使用 await
运算符标记暂停点,则该方法会作为同步方法执行,即使有 async
修饰符,也不例外。 编译器将为此类方法发布一个警告。