一、什么是同步?什么是异步?
在.net中,async 和 await 是两个关键字,async 关键字用于声明一个方法是异步方法,该方法可以包含一个或多个 await 表达式。await 关键字是用于在异步方法中等候一个使命(Task 或 Task<T>对象)的完成。在 async 方法中使用 await表达式时,会暂停当前方法的执行,直到等候的使命完成。在这段时间内,主线程可以去执行其它操纵。
什么是同步:当一个方法被调用时,调用者必要等候该方法执行完毕后才会继续往下执行,我们称这种方法为同步方法。
什么是异步:当一个方法被调用时立即返回,并获取一个线程执(Task)行该方法内部的业务逻辑,而调用者不必要等候这个方法执行完毕,我们称这种方法为异步方法。
二、async/await是怎么提高性能的?
异步的好处在于非阻塞(调用线程不会暂停执行去等候子线程完成),因此,我们可以把一些不必要立即使用结果、耗时的使命设为异步去执行,可以提高步伐的执行效率。
比如,一个主线程必要执行 5 个方法,假设每个方法的分别用时为 0.1s、0.2s、0.3s、0.4s、0.5s,如果在同步编程中,这个主线程的执行用时大概为1.5秒。而如果把这5个方法写成异步的形式,那么这个主线程大概用时为0.5秒。
这是为什么呢?这是由于,在同步方法中,主线程在调用方法时,必要把这个方法执行完成之后再继续调用后续的方法,主线程执行这5个方法就比如一根线穿5颗珠子一样,一颗一颗来,以是主线程执行所用时间大概为1.5秒。而在异步方法中,主线程在调用异步方法时,主线程不会立即去执行异步方法的,而是在碰到异步方法中的 await语句后返回一个使命(Task),然后再继续调用后续的方法,这些使命的执行是由 task创建一个子线程去执行的,主线程执行这5个异步方法就比如5个人拿5根线同时穿5颗珠子,所用时间就是用时最多的那个,以是主线程执行时间大概为0.5秒。
问题:怎么办理在调用异步函数时,主线程继续向下执行后,主线程是怎么接纳或管理这个异步方法的执行结果的。
1、await等候执行
- public class Demo
- {
- public async Task DemoAsync()
- {
- await Task.Delay(1000);
- Console.WriteLine("1秒后执行");
- }
- }
- public Class Program
- {
- static async Task Main(string[] args)
- {
- Demo demo = new Demo();
- // 使用 await 等待DemoAsync的执行
- await demo.DemoAsync();
- Console.ReadKey();
- }
- }
复制代码 2、使用事件
- internal class Program
- {
- static void Main(string[] args)
- {
- Demo demo = new Demo();
- demo.OnEvent += (() =>
- {
- Console.WriteLine("事件订阅");
- });
- demo.DemoAsync();
- Console.ReadKey();
- }
- }
- public class Demo
- {
- public event Action OnEvent;
- public async Task DemoAsync()
- {
- Console.WriteLine("开始执行");
- await Task.Delay(1000);
- Console.WriteLine("1秒后执行");
- OnEvent?.Invoke();
- }
- }
复制代码 3、回调函数
- internal class Program
- {
- static void Main(string[] args)
- {
- Demo demo = new Demo();
- demo.DemoAsync(() =>
- {
- Console.WriteLine("回调函数");
- });
- Console.ReadKey();
- }
- }
- public class Demo
- {
- public async Task DemoAsync(Action callback)
- {
- Console.WriteLine("开始执行");
- await Task.Delay(1000);
- callback?.Invoke();
- Console.WriteLine("1秒后执行");
- }
- }
复制代码 4、使用异步方法但不等候结果
这种方法知识启动了异步操纵而不必要结果,可以简单的调用异步方法而不使用 await。这种方式不会阻塞主线程,也不会处理异步操纵的结果。
- internal class Program
- {
- static void Main(string[] args)
- {
- Demo demo = new Demo();
- demo.DemoAsync();
- Console.ReadKey();
- }
- }
- public class Demo
- {
- public async Task DemoAsync()
- {
- Console.WriteLine("开始执行");
- await Task.Delay(1000);
- Console.WriteLine("1秒后执行");
- }
- }
复制代码 5、将异步结果存储在变量中
如果想要在某个时候获取到异步操纵中的结果,可以将异步操纵的结果存储在变量中,然后再访问它。
- internal class Program
- {
- static void Main(string[] args)
- {
- Demo demo = new Demo();
- var demoResult = demo.DemoAsync();
- // 使用 wait等待异步的完成
- demoResult.Wait();
- if (demoResult.IsCompleted)
- {
- Console.WriteLine("str执行完成");
- Console.WriteLine(demoResult.Result);
- }
- Console.ReadKey();
- }
- }
- public class Demo
- {
- public async Task<string> DemoAsync()
- {
- Console.WriteLine("开始执行");
- await Task.Delay(1000);
- Console.WriteLine("1秒后执行");
- return "异步返回结果";
- }
- }
复制代码 三、异步到底办理了什么?到底起到了什么样的作用?
1、提高相应性:使用 async 和 await 可以制止等候长时间运行的操纵(如 IO 操纵)阻塞主线程,从而提高应用步伐的相应性。
2、简化异步操纵:async 和 await 使得编写异步代码更接近同步代码的写法,这降低了异步编程的复杂性和堕落的概率。
3、优化资源使用:异步操纵答应线程在等候使命完成时释放,这样可以为其它使命腾出资源,而不是处于空闲等候状态。
四、在使用异步时的一些问题的办理
1、异步的传递性问题
异步方法的异步结果会在调用链上向上传递的,导致异步方法的调用链上的一些列方法也会被标记为异步。这种情况通常发生在下面场景中:
- 调用异步方法:如果一个方法调用了一个异步方法,那么这个方法也必要标记为 async,并使用 await 等候结果。
- 返回范例的变化:异步方法通常以 Task 或 Task<T> 范例返回,这意味着调用这些异步方法的其他方法也必要更新其返回范例以匹配 Task 或 Task<T> 。
异步方法的传递性的制止:
1、不使用 await 调用异步函数:如果在调用异步函数时,不必要等候异步函数的返回结果,那么可以不实用 await关键字调用异步函数。
2、使用 Task.Run 来启动异步操纵:Task.Run 方法可以用来启动一个新的异步操纵,它会提供一个新的使命来异步函数,从而制止了异步的传递性。
3、使用事件或回调来处理异步的结果:如果异步函数必要通知调用者操纵已完成,可以使用事件或回调来代替直接的 await 调用。
4、将异步结果存放在变量中:如果必要等候异步操纵的结果,但又不想立即等候它,可以将异步使命存储在变量中,然后在必要访问时使用 wait 方法来等候异步的完成。
好记性否则烂笔头,在学习的路上留下点痕迹。盼望能给大家带来帮助,也期待你的点赞和讨论。
若有不足之处,还请斧正。
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |