WebApi上传图片 await关键字

await关键字对于方法执行的影响

将上一篇WebApi上传图片中代码修改(使用了await关键字)如下:

        [HttpPost]
        public async Task<string> Post()
        {
            if (!Request.Content.IsMimeMultipartContent())
                throw new HttpResponseException(Request.CreateResponse(HttpStatusCode.NotAcceptable, "Invalid Request!"));
            //获取学员信息
            Student model = new Student()
            {
                Name = HttpContext.Current.Request.Form["StuName"],
                GroupName = HttpContext.Current.Request.Form["GroupName"],
                // ...
            };
            //获取学员通过科目名称
            string passSubject = HttpContext.Current.Request.Form["passSubject"];
            //获取学员未通过科目名称
            string noPassSubject = HttpContext.Current.Request.Form["passSubject"];
            Trace.WriteLine("begin 添加学员信息");
            //添加学员信息
            await stuService.AddStuByAsync(model).ContinueWith(p =>
           {
               long stuId = p.Result;
               Trace.WriteLine("begin 通过科目表");
               subjectService.AddPassSubject(passSubject, stuId);//添加此学员通过科目信息
               Trace.WriteLine("end 通过科目表");

               Trace.WriteLine("begin 未通过科目表");
               subjectService.AddNoPassSubject(noPassSubject, stuId);//添加此学员未通过科目信息
               Trace.WriteLine("end 未通过科目表");
           });
            Trace.WriteLine("end 添加学员信息");
            string path = System.Web.HttpContext.Current.Server.MapPath("~/Images/upload/");
            Trace.WriteLine("获取图片......");
            Request.Content.ReadAsMultipartAsync().ContinueWith(p =>
           {
               var content = p.Result.Contents;
               Trace.WriteLine("begin 图片");
               foreach (var item in content)
               {
                   if (string.IsNullOrEmpty(item.Headers.ContentDisposition.FileName))
                   {
                       continue;
                   }
                   item.ReadAsStreamAsync().ContinueWith(a =>
                 {
                     Stream stream = a.Result;
                     string fileName = item.Headers.ContentDisposition.FileName;
                     fileName = fileName.Substring(1, fileName.Length - 2);

                     Trace.WriteLine("图片名称:" + fileName);

                     //stream 转为 image
                     saveImg(path, stream, fileName);
                 });
               }
               Trace.WriteLine("end 图片");
           });
            return "ok";
        }

结果:

未加await  主线程和ContinueWith 里的子

线程都在执行

加了await  主线程会等待ContinueWith 里的子

线程

通过对比可以看出,加了await后,当方法执行到await这里,没有继续向下执行,而是等待await 后的方法执行完成后才继续向下执行。

也就是说遇到await时,当前线程会暂时停止,去等待await 后的方法执行完成。



添加一个新的方法 AddPassSubjectByAsync 此方法内没有使用到 await

添加学员信息的代码修改如下:

  Trace.WriteLine("begin 添加学员信息");
  //添加学员信息
  stuService.AddStuByAsync(model).ContinueWith(async p =>
  {
      Trace.WriteLine("begin 子线程2");
      long stuId = p.Result;
      subjectService.AddPassSubjectByAsync(passSubject, stuId).ContinueWith(a =>
      {
          Trace.WriteLine("子线程3");
      });
      Trace.WriteLine("end 子线程2");
  });
  Trace.WriteLine("end 添加学员信息");

运行结果:

可以看出子线程3运行的时候,子线程2和主线程也是在运行着。

那么接下来就是问题所在,如果子线程2中有await关键字,各个线程执行状态如何呢?

例1:

只有子线程中存在await,代码如下:

  Trace.WriteLine("begin 添加学员信息");
  //添加学员信息
  stuService.AddStuByAsync(model).ContinueWith(async p =>
  {
      Trace.WriteLine("begin 子线程2");
      long stuId = p.Result;
      await subjectService.AddPassSubjectByAsync(passSubject, stuId).ContinueWith(a =>
      {
           Trace.WriteLine("begin 子线程3");
           Trace.WriteLine("begin 未通过科目表");
           subjectService.AddNoPassSubject(noPassSubject, stuId);
           Trace.WriteLine("end 未通过科目表");
           Trace.WriteLine("end 子线程3");
      });
      Trace.WriteLine("end 子线程2");
 });
 Trace.WriteLine("end 添加学员信息");
 //测试线程3执行时主线程是否执行
 Trace.WriteLine("begin 测试");
 subjectService.GetSubjectList();//获取所有的科目信息
 Trace.WriteLine("end 测试");

结果:

通过前四行可看出主线程和子线程2都在执行。当子线程2执行到await 处,子线程2变为"暂停"状态,去执行子线程3,这时候主线程和子线程3在执行中 ( 从子线程3还未end,主线程已经开始执行测试可看出 )。

当子线程3执行完,子线程2从"暂停"状态唤醒,继续向下执行。

说明子线程2、3的执行状态并没有影响主线程。

例2:

都有await,代码如下:

   Trace.WriteLine("begin 添加学员信息");
   //添加学员信息
   await stuService.AddStuByAsync(model).ContinueWith(async p =>
   {
        Trace.WriteLine("begin 子线程2");
        long stuId = p.Result;
        await subjectService.AddPassSubjectByAsync(passSubject, stuId).ContinueWith(a =>
        {
            Trace.WriteLine("begin 子线程3");
            Trace.WriteLine("begin 未通过科目表");
            subjectService.AddNoPassSubject(noPassSubject, stuId);
            Trace.WriteLine("end 未通过科目表");
            Trace.WriteLine("end 子线程3");
        });
        Trace.WriteLine("end 子线程2");
   });
   Trace.WriteLine("end 添加学员信息");
   //测试线程3执行时主线程是否执行
   Trace.WriteLine("begin 测试");
   subjectService.GetSubjectList();//获取所有的科目信息
   Trace.WriteLine("end 测试");

结果:

通过输出的前两行可看出,主线程运行到await 处的时候,主线程 "暂停" ,等待子线程2返回结果。此时子线程2开始执行,同样运行到await 处的时候,子线程2 "暂停",

通过输出信息可看出子线程3执行时主线程会被"唤醒"( 这时子线程3和主线程都在执行中 )。当子线程3执行完成后,子线程2继续执行。

说明:当方法中遇到await关键字的时候,程序执行可分为两个部分。

1. 当前线程"暂停" ,去执行await后的方法( 如子线程2 )。

2. 如果主线程"暂停"状态时,主线程会被"唤醒"( 此时会有两个线程在执行,如主线程和子线程3 )。

时间: 2024-10-10 04:31:42

WebApi上传图片 await关键字的相关文章

kindeditor扩展粘贴图片功能&amp;修改图片上传路径并通过webapi上传图片到图片服务器

前言 kindeditor是一个非常好用的富文本编辑器,它的简单使用我就不再介绍了. 而kindeditor却对图片的处理不够理想. 本篇博文需要解决的问题有两个: kindeditor扩展粘贴图片功能 kindeditor修改图片上传路径并通过webapi上传图片到图片服务器(支持分布式图片) 结果演示 1.扩展粘贴图片功能演示 2.修改图片上传路径演示: 我们的网站演示地址是:http://localhost:9393/ 我们的图片服务器地址是:http://localhost:9394/

async和await关键字实现异步编程

async和await关键字实现异步编程 异步编程 概念 异步编程核心为异步操作,该操作一旦启动将在一段时间内完成.所谓异步,关键是实现了两点:(1)正在执行的此操作,不会阻塞原来的线程(2)一旦启动的此操作,可以继续执行其他任务.当该操作完成时,将调用回调函数来通知该操作已经结束. [注]:本人一直以为同步和异步都属于多线程的范畴,到今天才明白完全错误,异步和多线程是属于不同范畴,多线程和异步是并发的两种形式,并行处理和线程同步是多线程的两种形式,这是我当前的理解,不知是否有误,文中若有错误,

.net 异步编程async &amp; await关键字的思考

C# 5.0引入了两个关键字 async和await,这两个关键字在很大程度上帮助我们简化了异步编程的实现代码,而且TPL中的task与async和await有很大的关系 思考了一下异步编程中的async & await关键字,对两个关键字尤其是await关键字一直很迷糊,因此深入思考了一下.首先借助的示例是:[你必须知道的异步编程]C# 5.0 新特性--Async和Await使异步编程更简单这是博客园一个大牛写的,自己也一直关注这个大神,不得不说,博客园大神很多,而且氛围也很好.我引入了其中

异步编程Async/await关键字

异步编程Async \await 关键字在各编程语言中的发展(出现)纪实. 时间 语言版本 2012.08.15 C#5.0(VS2012) 2015.09.13 Python 3.5 2016.03 ECMAScript 2016 (ES7) C#中的用法和浅层次原理 我是占位代理 Python中的用法,和协程 我是占位代理 Javascript中的说明 我是占位代理,不懂具体用法.

异步编程,采用WorkgroupWorker,async和await关键字

金科玉律:不要在UI线程上执行耗时的操作:不要在除了UI线程之外的其他线程上访问UI控件! NET1.1的BeginInvoke异步调用,需要准备3个方法:功能方法GetWebsiteLength,结果方法DownloadComplete,呼叫方法BeginInvoke! 但很不幸,在UI线程之外访问UI线程控件!调用失败.线程同步必须在线程所属进程的公共区域保留同步区,以此实现线程间的通讯. 二.C#2.0引入了BackgroundWorker,从而极大的简化了线程间通讯. 三.C#4.0引入

Async 与 Await 关键字研究

1        Aynsc 和 Await 关键字的研究 在 .NET 4.0 以后,基于 Task 的异步编程模式大行其道,因其大大简化了异步编程所带来的大量代码工作而深受编程人员的欢迎,如果你曾经使用过 APM(基于 IAsyncResult) 和 EAP( 基于 event/delegate),那么你一定感受颇深. 而随之而来.NET 4.5 的两个关键字 async 和 await 又使得异步编程如编写顺序的代码一样容易,特别是 async 对 委托(Lamda/LINQ 表达式,匿名

可移植类库无法使用async、await关键字

今天遇到了如题所示的问题,平台已经选择了.net 4.5了,可是就是编译不通过,await关键字下出现了红色下划线. 解决方法:安装一个Bcl的补丁包. https://www.nuget.org/packages/Microsoft.Bcl.Async 安装完成后就能编译通过了.

C#中如果用await关键字来await一个为null的Task对象会抛出异常

await & async模式是C#中一个很重要的特性,可以用来提高异步程序(多线程程序)的执行效率.但是如果尝试用await关键字来await一个为null的Task对象,会导致程序抛出NullReferenceException异常. 新建一个.NET Core控制台项目,贴入如下代码: using System; using System.Threading; using System.Threading.Tasks; namespace AwaitNull { class Program

教你正确打开async/await关键字的使用

这段时间在项目开发中看到了一些async/await的使用,在aspnet core的host组件源码中也看到了许多的async/await代码.在开发时,正确的使用了async/await是可以提高程序的性能.下面的代码教你正确的理解await关键字的暂停/阻塞方法调用: static void Main(string[] args) { Console.WriteLine("-------主线程启动-------"); var task = GetStrLengthAsync();