微软的Task已经出来很久了,一直没有去研究,以为就是和Thread差不多的东西。直到最近看到了Task的使用介绍,发现比Thread的语法要精炼多了,于是便在项目中用上了。

结果就出问题了,数据库连接池用一段时间就满了,排除了各种原因,最后开始怀疑是不是Task有什么不为人知的隐患。

由于对Task的使用只是停留在开一个线程去执行一个不需要返回结果的任务这种阶段。为了查明是否是Task引起的线程池满,便开始各种查资料。

最终的结果是,连接池满是因为程序中的一个SqlConnection没有关闭,和Task没有半毛钱关系......

问题解决了。Task也研究的差不多了。

下面我们来谈一下Task的使用.....

开启一个Task

开启task有以下三种方式,曾经一度纠结在到底该用哪种方式来开始一个任务,最终发现其实在没有特殊要求的情况下,这三种方式除了语法不同外,执行方式和结果是一样的

 Task<int> t1 = Task.Factory.StartNew(() => { Task.Delay(); return ; });
Task<int> t2 = new Task<int>(() => { Task.Delay(); return ; });
t2.Start();
Task<int> t3 = Task.Run(() => { Task.Delay(); return ; });

上面的示例返回一个数字,所以接收者是Task的泛型,同样也可以执行一个不带返回结果的函数。

Task返回值

1.可以直接通过Task .Result属性来获取Task的结果

使用这种方式来获取结果,主线程会等待Task执行完成。也就是说,用这种方式来获取Task的返回结果,和不使用Task并没有什么区别。

但是需要注意的是,慎用.Result或者Wait来获取Task的返回值,除非你明确地知道Task的代码逻辑。我们来看下面一段代码

当点击button2时,应用程序会卡死。因为在调用.Result时,UI线程会阻塞,

而我们给GetResult的任务指出需要用UI线程来执行任务中的代码。

UI线程在等待GetResult完成,却又无法去运行GetResult中的代码。造成死锁

2.await 和 async

先上一个测试代码

 static void Main(string[] args)
{
Console.WriteLine("程序启动");
Task<int> t = GetNum();
Console.WriteLine("主线程继续执行");
int num = t.Result;
Console.WriteLine("主线程获取到数字:" + num);
} public static async Task<int> GetNum()
{
Console.WriteLine("GetNum函数进入");
int num = await Task.Run(() => { Task.Delay(); return ; });
Console.WriteLine("GetNum函数获取到数字:"+num);
return num;
}

await 运算符只能用于异步方法中,所以包含await运算符的方法都需要有async修饰符来修饰,称之为异步方法。

通过实验,我们看到在异步函数中,遇到await运算符之后,主线程就继续往下执行了,更确切的解释是,Main函数开始和GetNum函数并行执行,

直到获取t.Result时,若GetNum()函数仍未执行完毕,Main函数则需要等待GetNum返回。

在GetNum函数中,await后面的代码需要等待await的Task执行完成后方可执行,等同于下面不适用await的代码

  static void Main(string[] args)
{
Console.WriteLine("程序启动");
Task<int> t = GetNumNoAwait();
Console.WriteLine("主线程继续执行");
int num = t.Result;
Console.WriteLine("主线程获取到数字:" + num);
Console.Read();
} public static Task<int> GetNumNoAwait()
{
Console.WriteLine("GetNum函数进入");
Task<int> t = Task<int>.Run(() => { Task.Delay(); return ; });
t.ContinueWith(m => { Console.WriteLine("GetNum函数获取到数字:" + m.Result); });
return t;
}

通过await来获取返回值的操作,比前一种方式的优点在于他不会阻塞主线程的。这一点在winform或wpf等gui程序上可以很明显地提现出来

Task在winform中的使用

这是一个winform程序的代码片段,页面中有两个按钮,我们用maketext函数来模拟一个需要耗时的比如调用api获取数据的操作。

当点击button1时程序会一直等待结果返回,期间窗体无法拖动

而用异步方法则不会阻塞主窗体的其他操作

AsyncController

看过很多在Action中使用异步action的文章,并以此和未使用异步的Action来进行网站吞吐量的对比。

大概的代码类似于下面这样


最终都会得出一个结论,以上代码的吞吐量要远远高于未使用异步的

当时我就很不解,await就是在等待异步代码执行完成,并不会释放请求占用的线程,为什么会提升网站的吞吐量呢?

经过各种实验,仍然无法来证明以上代码的写法会使得网站的吞吐量更高,反而大多数情况下,效率稍微低了一些

(刚刚看过一本书中有介绍,通常的方法调用比使用async关键字的同样方法调用要快上40-50倍。所以异步函数在合适的场景被正确地使用也是非常重要的)

最终看了Msdn上关于异步控制器的介绍,方才找到正确的写法

以下是截取MSdn上的代码片段

首先使用 AsyncManager.OutstandingOperations.Increment()函数来设定未完成的请求操作,默认是1,然后每一个异步操作完成,通过Decrement来使计数器减1,当计数器归零之后,则会调用xxxCompleted函数来返回结果。

这样解释就行的通了,当执行完NewsAsync中的代码之后,请求线程就会释放,直到异步函数执行完成,系统会重新获取一个线程通过NewsCompleted来返回给客户端执行结果。

下面是我的测试代码

 public class TaskTestController : AsyncController
{
public void GetDataAsync()
{
AsyncManager.OutstandingOperations.Increment();
WebClient client = new WebClient();
client.DownloadDataCompleted += (sender, e) =>
{
AsyncManager.Parameters["bytelength"] = e.Result.Length;
AsyncManager.OutstandingOperations.Decrement();
};
client.DownloadDataAsync(new Uri("https://docs.microsoft.com/zh-cn/dotnet/framework/get-started/"));
}
public int GetDataCompleted(int bytelength)
{
return bytelength;
}
}
 public class TaskTest1Controller : Controller
{
public int GetData()
{
WebClient client = new WebClient();
var rsu = client.DownloadData(new Uri("https://docs.microsoft.com/zh-cn/dotnet/framework/get-started/"));
return rsu.Length; ;
}
}

然后我进行模拟1000个并发2000条请求,下面是测试结果

这里就可以看到异步控制器的优势已经显露出来了

然后我将iis的最大并发设置为10,模拟了一个20并发200条请求的操作,

异步控制器用时3.001s,失败0条

普通控制器用时4.551s,失败8条

测试完成,希望对有需要的人有所帮助

Task及Mvc的异步控制器 使用探索的更多相关文章

  1. ASP.NET MVC EF 中使用异步控制器

    最近悟出来一个道理,在这儿分享给大家:学历代表你的过去,能力代表你的现在,学习代表你的将来. 十年河东十年河西,莫欺少年穷 学无止境,精益求精   为什么使用异步操作/线程池 ASP.NET MVC ...

  2. ASP.NET MVC中使用异步控制器

    线程池 一直想把项目改写成异步,但是ASP.NETMVC3下写的过于繁琐,.NET 4.5与ASP.NET MVC下代码写起来就比较简单了, MS好像也一直喜欢这样搞,每一个成熟的东西,都要演变好几个 ...

  3. ASP.NET MVC 学习笔记-6.异步控制器

    1)         异步控制器的由来 对于IIS,它维护了一个.NET线程池来处理客户端请求,这个线程池称为工作线程池,其中的线程称为工作线程.当IIS接收到一个请求时,需要从工作线程池中唤醒一个工 ...

  4. c#异步编程(三)—ASP.NET MVC 异步控制器及EF异步操作

    ASP.NET MVC 异步控制器及EF异步操作 异步控制器 ASP.NET MVC2后开始了对异步请求管道的支持,异步请求管道的作用是允许web服务器处理长时间运行的请求,比如 那些花费大量时间等待 ...

  5. 在 ASP.NET MVC 中使用异步控制器

    线程池 一直想把项目改写成异步,但是ASP.NETMVC3下写的过于繁琐,.NET 4.5与ASP.NET MVC下代码写起来就比较简单了, MS好像也一直喜欢这样搞,每一个成熟的东西,都要演变好几个 ...

  6. ASP.NET MVC 学习笔记-7.自定义配置信息 ASP.NET MVC 学习笔记-6.异步控制器 ASP.NET MVC 学习笔记-5.Controller与View的数据传递 ASP.NET MVC 学习笔记-4.ASP.NET MVC中Ajax的应用 ASP.NET MVC 学习笔记-3.面向对象设计原则

    ASP.NET MVC 学习笔记-7.自定义配置信息   ASP.NET程序中的web.config文件中,在appSettings这个配置节中能够保存一些配置,比如, 1 <appSettin ...

  7. 看stackoverflow大牛如何回答何时在ASP.NET中使用异步控制器?

    转载自博客园:http://farb.cnblogs.com/ 今天无意中看到stackoverflow上一个很好的问答,个人觉得很有价值,所以翻译过来和大家共享!希望大家能相互交流. 在ASP.NE ...

  8. MVC 4 异步编程简化了

    MVC 3 异步编程好麻烦,需要使用异步控制器,一个Action需要拆成两个,很不方便.MVC3的好处是,只需要.NET Framework 4.0就能运行 MVC 4 之后只需要使用async和aw ...

  9. ASP.NET MVC学习之控制器篇扩展性

    原文:ASP.NET MVC学习之控制器篇扩展性 一.前言 在之前的一篇随笔中已经讲述过控制器,而今天的随笔是作为之前的扩展. 二.正文 1.自定义动作方法 相信大家在开发过程一定会遇到动作方法的重名 ...

随机推荐

  1. 【JVM命令系列】jstat

    命令基本概述 Jstat是JDK自带的一个轻量级小工具.全称"Java Virtual Machine statistics monitoring tool",它位于java的bi ...

  2. Day3 Python基础学习——文件操作、函数

    一.文件操作 1.对文件操作流程 打开文件,得到文件句柄并赋值给一个变量 通过文件句柄对文件进行操作 关闭文件 #打开文件,读写文件,关闭文件 http://www.cnblogs.com/linha ...

  3. 如何创建一个Django项目

    Django 软件框架 软件框架是由其中的各个模块组成,每个模块负责特定的功能,模块与模块之间相互协作来完成软件开发. MVC简介 MVC框架的核心思想是:解耦,让不同的代码块之间降低耦合,增强代码的 ...

  4. Github Page+Bmob实现简单动态功能

    Github Page基于jekyll能够实现简单的静态网站,但是没有提供后端服务.目前国内外也有很多提供后台服务,特别是云服务.譬如国外有AWS,记得好像是注册免费使用一年:再如Heroku,支持N ...

  5. PHP多进程编之僵尸进程问题

    上一篇说到了使用pcntl_fork函数可以让PHP实现多进程并发或者异步处理的效果.那么问题是我们产生的进程需要去控制,而不能置之不理.最基本的方式就是fork进程和杀死进程. 通过利用pcntl_ ...

  6. 吾八哥学Python(四):了解Python基础语法(下)

    咱们接着上篇的语法学习,继续了解学习Python基础语法. 数据类型大体上把Python中的数据类型分为如下几类:Number(数字),String(字符串).List(列表).Dictionary( ...

  7. Visual studio 创建项目失败vstemplate

    Visual studio 创建项目失败 提示 the vstemplate file references the wizard class 'Microsoft.VisualStudio.WinR ...

  8. Latex 论文elsevier,手把手如何用Latex写论文

    这几天在开始写论文,准备发的是elsevier,这个网站的instruction有问题,下载的东西基本上好多的错误,所以我就写博客记录. 首先看下:https://www.elsevier.com/a ...

  9. 彻底了解构建 JSON 字符串的三种方式

    原创播客,如需转载请注明出处.原文地址:http://www.cnblogs.com/crawl/p/7701856.html 前言:JSON 是轻量级的数据交换格式,很常用,尤其是在使用 Ajax ...

  10. Python 初学者 入门 应该学习 python 2 还是 python 3?

    许多刚入门 Python 的朋友都在纠结的的问题是:我应该选择学习 python2 还是 python3? 对此,咪博士的回答是:果断 Python3 ! 可是,还有许多小白朋友仍然犹豫:那为什么还是 ...