转载源:小宅博客C#第30节:http://www.bilibili996.com/Course?id=4688450000043
源码下载地址,提取码:sa4x
https://pan.baidu.com/s/109_JBTGTjUXVFS4cewEOuA
一、什么是异步
同步和异步主要用于修饰方法。
当一个方法被调用时,调用者需要等待该方法执行完毕并返回才能继续执行,我们称这个方法是同步方法;
当一个方法被调用时立即返回,并获取一个线程执行该方法内部的业务,调用者不用等待该方法执行完毕,我们称这个方法为异步方法。
异步的好处在于非阻塞(调用线程不会暂停执行去等待子线程完成),因此我们把一些不需要立即使用结果、较耗时的任务设为异步执行,可以提高程序的运行效率。
net4.0在ThreadPool的基础上推出了Task类,微软极力推荐使用Task来执行异步任务,现在C#类库中的异步方法基本都用到了Task;
net5.0推出了async/await,让异步编程更为方便。本篇主要介绍Task、async/await相关的内容,其他异步操作的方式会在下一篇介绍。
二、Task介绍
Task是在ThreadPool的基础上推出的,我们简单了解下ThreadPool。
ThreadPool中有若干数量的线程,如果有任务需要处理时,会从线程池中获取一个空闲的线程来执行任务,任务执行完毕后线程不会销毁,而是被线程池回收以供后续任务使用。
当线程池中所有的线程都在忙碌时,又有新任务要处理时,线程池才会新建一个线程来处理该任务,如果线程数量达到设置的最大值,任务会排队,等待其他任务释放线程后再执行。线程池能减少线程的创建,节省开销.
三、async/await介绍
async/await是基于Task的,而Task是对ThreadPool的封装改进,主要是为了更有效的控制线程池中的线程(ThreadPool中的线程,我们很难通过代码控制其执行顺序,任务延续和取消等等);
ThreadPool基于Thread的,主要目的是减少Thread创建数量和管理Thread的成本。
async/await Task是C#中更先进的,也是微软大力推广的特性,我们在开发中可以尝试使用Task来替代Thread/ThreadPool,处理本地IO和网络IO任务是尽量使用async/await来提高任务执行效率。
四、项目案例:
效果如下:
代码如下:
using System;
using System.Collections.Generic;
using System.Text;
namespace WindowsFormsApp
{
public class Contents
{
public static readonly IEnumerable<string> WebSites = new string[]
{
"https://www.zhihu.com",
"https://www.baidu.com",
"http://www.bilibili996.com/Course?id=4688450000043"
//"https://www.weibo.com", //有些地址进行了反爬,或者失效了,无法访问
//"https://www.stackoverflow.com",
//"https://docs.microsoft.com",
//"https://docs.microsoft.com/aspnet/core",
//"https://docs.microsoft.com/azure",
//"https://docs.microsoft.com/azure/devops",
//"https://docs.microsoft.com/dotnet",
//"https://docs.microsoft.com/dynamics365",
//"https://docs.microsoft.com/education",
//"https://docs.microsoft.com/enterprise-mobility-security",
//"https://docs.microsoft.com/gaming",
//"https://docs.microsoft.com/graph",
//"https://docs.microsoft.com/microsoft-365",
//"https://docs.microsoft.com/office",
//"https://docs.microsoft.com/powershell",
//"https://docs.microsoft.com/sql",
//"https://docs.microsoft.com/surface",
//"https://docs.microsoft.com/system-center",
//"https://docs.microsoft.com/visualstudio",
//"https://docs.microsoft.com/windows",
//"https://docs.microsoft.com/xamarin"
};
}
}
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Net.Http;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace WindowsFormsApp
{
public partial class Form1 : Form
{
private readonly HttpClient httpClient = new HttpClient();
public Form1()
{
InitializeComponent();
}
//窗体加载事件
private void Form1_Load(object sender, EventArgs e)
{
//清空文本框内容
textBox1.Text = "";
}
//点击同步加载
private void button1_Click(object sender, EventArgs e)
{
//清空文本框
//textBox1.Text = "";
//程序开始时间
var stopwatch = Stopwatch.StartNew();
//同步加载地址信息
DownloadWebsitesSync();
//加载文本信息
textBox1.Text += $"同步加载效果如上: Elapsed time: {stopwatch.Elapsed}{Environment.NewLine}";
textBox1.Text += "=================================================================================";
}
//点击异步加载
private async void button2_Click(object sender, EventArgs e)
{
//清空文本框
//textBox1.Text = "";
//程序开始时间
var stopwatch = Stopwatch.StartNew();
//异步加载文本信息
await DownloadWebsitesAsync();
//加载文本信息
textBox1.Text += $"异步加载效果如上: Elapsed time: {stopwatch.Elapsed}{Environment.NewLine}";
textBox1.Text += "=================================================================================";
}
//拼接文本内容
private void ShowLog(string result)
{
textBox1.Text += $"\n{result}\n";
}
#region Button1同步加载
private void DownloadWebsitesSync()
{
//遍历地址容器
foreach (var site in Contents.WebSites)
{
var result = DownloadWebSiteSync(site);
ShowLog(result);
}
}
//返回同步请求地址结果
private string DownloadWebSiteSync(string url)
{
//httpClient get请求地址,获取返回值
var response = httpClient.GetAsync(url).GetAwaiter().GetResult();
var responsePayloadBytes = response.Content.ReadAsByteArrayAsync().GetAwaiter().GetResult();
//返回请求结果
return $"Finish downloding data from {url}. Total bytes returned {responsePayloadBytes.Length}. {Environment.NewLine}";
}
#endregion
#region Button2异步加载
private async Task DownloadWebsitesAsync()
{
//承载Task<string>容器
List<Task<string>> downloadwebTasks = new List<Task<string>>();
//遍历地址容器
foreach (var site in Contents.WebSites)
{
downloadwebTasks.Add(DownloadWebsitesAsync(site));
//var result = await Task.Run(() => DownloadWebSiteSync(site));
//ShowLog(result);
}
var res = await Task.WhenAll(downloadwebTasks);
foreach (var item in res)
{
ShowLog(item);
}
}
//返回异步请求地址结果
private async Task<string> DownloadWebsitesAsync(string url)
{
var response = await httpClient.GetAsync(url);
var responsePayloadBytes = await response.Content.ReadAsByteArrayAsync();
return $"Finish downloading data form {url}. Total bytes returned {responsePayloadBytes.Length}. {Environment.NewLine}";
}
#endregion
}
}