河口建设局网站,上海网络关键词优化,商务网站建设设计结构内容,精准营销的三要素之前给大家介绍了所谓异步编程的用法#xff0c;但是没有细致的理解到#xff0c;今天想和大家一起探讨一下;
前文#xff1a;
C#笔记14 异步编程Async#xff0c;await#xff0c;task类-CSDN博客
异步的起初
应用程序会启动一个进程#xff0c;一个进程可以有很多…之前给大家介绍了所谓异步编程的用法但是没有细致的理解到今天想和大家一起探讨一下;
前文
C#笔记14 异步编程Asyncawaittask类-CSDN博客
异步的起初
应用程序会启动一个进程一个进程可以有很多线程。
如果一个线程我们给他命名为主线程。
这个线程如果一直往下走只有一条线这就是单线程。
还是这个线程如果它运行的途中创建了新的小伙伴去执行其他任务这就是多线程。
现在我们的主线程正在做着自己的事情类似于展示一个界面之类的此时创建一个线程去后台执行其他任务主线程不去管它这就是异步。
所以多线程的起初就是异步的。
同步的出现
现在主线程创建了两个小弟两个小弟功能差不多这两个小弟为了抢占一个资源打起来了。这可不行对吧于是我们就设立各种同步机制和同步锁控制他们学会等待。
等待的方式各不相同但是毫无疑问线程间互相有了约束和阻塞。
到这里其实我们想做的事情已经基本完成了。
线程各司其职遇到资源就进行同步机制的等待和唤醒操作。
但是还是会有问题比如多线程的管理小弟太多了根本管不过来小弟之间使用资源的调度原则不够公平等等。当然了这要求程序员的管理和操作系统的调度配合。
除此之外也发现管理多线程的方式不够先进
管理的困难
主线程是老大今天派小弟出去办事小弟办事之后确实办完了但是主线程不知道小弟已经办完了这时候是不是有小伙伴要想到C#中的委托和事件了
这样就可以让小弟通知老大哥自己做好了老大哥订阅了小弟的这个事件这样就能在小弟完成事件的时候执行对应的方法了。
但是每一个小弟都这样老大哥要手动管理这些事件就好像老大哥每天都得坐在办公室听汇报了一样尤其是管理线程的我们觉得很烦这个组织太杂乱了
尤其是什么情况需要反复派出小弟去干活的时候比如密集的io环境我们还要和每个小老弟都约定一个事件啥时候通知老大哥。
尤其是线程一多老大哥虽然不迷糊但是老大哥也很烦但是我们程序员也就是负责真正管理小弟的人迷糊了。这可怎么办
此时
如果不派小弟去干自己干老大哥自己的事情就做不好了。阻塞
如果派出小弟让小弟自己干自己的老大又不知道到底干的什么情况了就算小弟已经把结果搞出来了已经通过什么形式提交了也不知道。多线程异步
如果手动告诉小弟怎么通知老大这下倒是可以了但是咱们秘书程序员可怜了天天就负责管理每个小弟告诉小弟在哪告诉老大然后记下老大小弟给的数据怎么处理用什么方法处理。事件通知的多线程
到这我们秘书就想到一个方法减轻自己的工作量。将社团改组大哥和小弟都不是按所谓线程来做事了而是新的机制或者说不同的任务处理者Task。
新的处理异步的方法
async和await出场 async用于标记一个方法是异步的告诉编译器这个方法会有异步操作。该方法仍然可以在线程池中调度执行任务但这个并不由 async 本身控制。 await用于等待异步操作完成而不会阻塞当前线程。它只会让出控制权让当前线程去做其他事情当操作完成时再继续执行后续代码。 async标记一个事情告诉老大和小弟这个事情是异步的这个事情要让小弟去干不能影响老大哥工作。所以这个方法使用之后会立刻返回一个任务的引用作为结果等到事情办完了这个结果才会被填充为指定的值。
await专门用来调用一个需要耗时间的操作调用之后会让出控制权等到再次获取控制权也就是后面等待的操作有结果的时候如果异步方法有返回值的话await还会自动把值从结果里拿出来给指定的对象。
老大哥调用异步方法就像派出一个小弟task作为方法的返回值就像小弟给大哥留的纸条等到小弟任务完成了这个纸条上就会出现结果。这中间呢纸条就放在这里。
await是逻辑上的等待这个结果如果这个结果没有出现后面的逻辑就不会执行。
意思是老大虽然后面有些事要等待这个事情不代表老大就抛下自己手上的事情了实际上老大还是在干活的。
你会发现小弟中间也会有一些await操作。
老大哥一调用这个事情啊可以使用task意思就是老大哥派出了这个小弟但是自己没有去干奥这个小东西就是小弟留给老大的小纸条
await就是小弟告诉老大“好现在该到这里了我得等某个任务完成了才能继续。
意思是什么小弟办事也不是说立刻就办完了。也就是我们的方法内部也许还有耗时间的更具体的操作比如老大让小弟读写一批文件小弟可能要一个个文件读写这就是小弟给老大的纸条。
await 就像说“等这个任务做完了再通知我我再继续往下走。”
所以await 的作用是让程序在某个任务完成之前不阻塞其他操作。它并不会傻傻等着而是会继续处理其他的事情等到这个耗时操作完成后再回到你指定的位置继续执行。
using System;
using System.Net.Http;
using System.Threading.Tasks;class Program
{static async Task Main(string[] args){Console.WriteLine(${DateTime.Now:HH:mm:ss} - 大哥开始做事我让小弟去下载文件);// 大哥派小弟去干下载文件的活Task downloadTask 小弟去下载文件Async(http://example.com/largefile);// 大哥自己继续干活for (int i 0; i 10; i){Console.WriteLine(${DateTime.Now:HH:mm:ss} - 大哥我在忙别的事... {i});await Task.Delay(1000); // 模拟大哥处理别的事情需要一些时间}// 等小弟把下载任务做完await downloadTask;Console.WriteLine(${DateTime.Now:HH:mm:ss} - 大哥小弟终于把文件下载完了事情都做完了收工);}// 小弟去下载文件过程可能很久static async Task 小弟去下载文件Async(string url){Console.WriteLine(${DateTime.Now:HH:mm:ss} - 小弟开始下载文件...);using (HttpClient client new HttpClient()){// 模拟下载文件的耗时操作await Task.Delay(5000); // 假装下载需要5秒钟Console.WriteLine(${DateTime.Now:HH:mm:ss} - 小弟文件下载完了);}}
}10:00:00 - 大哥开始做事我让小弟去下载文件 10:00:00 - 小弟开始下载文件... 10:00:00 - 大哥我在忙别的事... 0 10:00:01 - 大哥我在忙别的事... 1 10:00:02 - 大哥我在忙别的事... 2 10:00:03 - 大哥我在忙别的事... 3 10:00:04 - 大哥我在忙别的事... 4 10:00:05 - 小弟文件下载完了 10:00:05 - 大哥我在忙别的事... 5 10:00:06 - 大哥我在忙别的事... 6 10:00:07 - 大哥我在忙别的事... 7 10:00:08 - 大哥我在忙别的事... 8 10:00:09 - 大哥我在忙别的事... 9 10:00:09 - 大哥小弟终于把文件下载完了事情都做完了收工 可以看出来大哥在派出小弟之后自己还在做事事实上小弟此时也正在下载文件。注意这里的小弟不是某个特定的我们管理的线程而是被我们的系统指派的线程池甚至就是操作系统在做。
大哥的await就是等小弟。
小弟的await就是小弟等小弟。
注意await不会让后面的代码提前执行反而是会就像顺序执行一样来执行。
但是它这种等待和我们之前线程的等待又不太一样因为这种等待是代码让出控制权给其他方法去执行。
异步方法之间的依赖
小弟之间也存在依赖的时候呢就可以像下面一样了。
using System;
using System.Threading.Tasks;class Program
{static async Task Main(string[] args){Console.WriteLine(${DateTime.Now:HH:mm:ss} - 老大哥开始派小弟A去下载文件);// 小弟A开始下载文件小弟B等他下载完Task 小弟A的任务 小弟A去下载文件Async();Task 小弟B的任务 小弟B等小弟A再处理文件Async(小弟A的任务);Console.WriteLine(${DateTime.Now:HH:mm:ss} - 老大哥我先干点其他的事...);// 等两个任务都完成await Task.WhenAll(小弟A的任务, 小弟B的任务);Console.WriteLine(${DateTime.Now:HH:mm:ss} - 老大哥小弟们都完成了我收工);}static async Task 小弟A去下载文件Async(){Console.WriteLine(${DateTime.Now:HH:mm:ss} - 小弟A开始下载文件...);await Task.Delay(3000); // 模拟耗时的下载过程Console.WriteLine(${DateTime.Now:HH:mm:ss} - 小弟A文件下载完了);}static async Task 小弟B等小弟A再处理文件Async(Task 小弟A的任务){Console.WriteLine(${DateTime.Now:HH:mm:ss} - 小弟B我得等小弟A下载完才能干活...);await 小弟A的任务; // 等待小弟A的任务完成Console.WriteLine(${DateTime.Now:HH:mm:ss} - 小弟B现在小弟A下载完了我开始处理文件...);await Task.Delay(2000); // 模拟文件处理时间Console.WriteLine(${DateTime.Now:HH:mm:ss} - 小弟B文件处理完了);}
}事实上任务机制可以让我们像写同步代码一样来写一些需要异步的操作。
同样的代码逻辑实际的执行上就会不同。
这和传统线程管理的方式不同避免了管理线程和事件订阅以及那种嵌套回调函数的麻烦。
这只是当下我浅薄的理解如果我说的有错请帮我指出感谢。