首页 > 代码库 > WebApi上传图片 await关键字

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 )。

 

WebApi上传图片 await关键字