什么是异步编程
举个栗子:洗衣机洗衣服需要60分钟,而在60分钟里我可以洗澡,写代码;洗衣机洗好衣服后我去晾衣服 晾完后,我再接着继续写代码;
同步跟异步
- 同步方法:可以认为程序是按照你写这些代码时所采用的顺序执行相关的指令的。
- 异步方法:可以在尚未完成所有指令的时候提前返回(如上面的洗衣服过程没执行完就返回去洗澡了),等到该方法等候的那项任务执行完毕后,在令这个方法从早前还没执行完的那个地方继续往下运行(如:衣服洗好晾好后,继续敲代码)
async,await的基本用法关键字
- 异步方式的返回值一般是
Task<T>
,T是真正的返回值,Task<int>
。惯例:异步方法名以Async
结尾; - 即使方法没有返回值,也最好把返回值声明为非泛型的
Task
。 - 调用泛型方法时, 一般在放方法前加上
await
调用,则这个方式也必须修饰为async
- 异步方式的 “传染性”:一个方式中如果有
awatit
调用,则这个方法也必须修饰为async
using System;
using System.IO;
using System.Threading.Tasks;
namespace 异步编程练习2
{
class Program
{
static async Task Main(string[] args) //传染性 加async
{
string fileName = @"E:\1.txt";
File.Delete(fileName);
await File.WriteAllTextAsync(fileName,"Hello"); //调用Async方法时,加await关键字
string s = await File.ReadAllTextAsync(fileName); //方法以 Asyns 结尾
Console.WriteLine(s);
}
}
}
编写异步方法
- 如果有同样的功能,既有同步方法,又有异步方法,那么优先使用异步方法;
class Program
{
static async Task Main(string[] args)
{
await TasDownloadHtmlAsync("https://www.baidu.com", @"E:\1.txt");
Console.WriteLine("完成!");
}
static async Task TasDownloadHtmlAsync(string url,string fileName)
{
using (HttpClient httpClient = new HttpClient())
{
string html = await httpClient.GetStringAsync(url);
await File.WriteAllTextAsync(fileName,html);
}
}
}
async,await 原理
- async 的方法会被 C# 编译器编译成一个类
- 会对 await 调用进行拆分为多个状态 (switch case)
- 对 async 方法的调用会被拆分为 MoveNext 的调用
- 用await 看似 “等待”,编译过后 其实并没有等待“wait”
async 和 多线程 的区别
- await 调用的等待期间,.net会把当前的线程返回给线程池,等异步方法调用执行完毕后,框架会从线程池再取出来一个线程执行后续的代码。(我没理解)
- 优化:要等待的时候,如果发现已经执行结束,那就们没有比较再切换线程;剩下的代码继续在之前的线程上继续执行;
using System;
using System.IO;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace async和多线程的区别
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine(Thread.CurrentThread.ManagedThreadId);
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 1000000; i++)
{
sb.Append("+++++++++++");
}
File.WriteAllTextAsync(@"E:\test.txt",sb.ToString());
Console.WriteLine(Thread.CurrentThread.ManagedThreadId);
}
}
}