使用Task异步执行方法_多线程_应用程序池
偶然遇到在执行登录的方法需要发送消息队列导致登录时间过长的问题,从网上查了一些方法,先将一个简单的异步处理程序的小例子展示出来,供大家参考:
备注:该方法是从应用程序程序所在的线程池中获取线程,第一次创建异步线程可能会费用一些时间,创建后不会立即销毁,以便其他线程多次重复使用,对程序性能影响不大:
//异步执行修改用户登录时间并发送队列--20171209-lixh
Task.Run(() =>
{
UserInfoBIZ.UpdateUserInfo(userInfo, ConfigSetting.SITEID, ConfigSetting.WEB_SITE_NAME, EPlatform.PC端);
});
本文转载地址:https://www.cnblogs.com/durow/p/4826653.html
以下是转载全文:
0x00 引言
之前写程序的时候在遇到一些比较花时间的操作例如HTTP请求时,总是会new一个Thread处理。对XxxxxAsync()之类的方法也没去了解过,倒也没遇到什么大问题。最近因为需求要求用DevExpress写界面,跑起来后发现比Native控件效率差好多。这才想到之前看到的“金科玉律”:不要在UI线程上执行界面无关的操作,因此集中看了下C#的异步操作,分享一下自己的比较和总结。
0x01 测试方法
IDE:VS2015 Community
.NET版本:4.5
使用函数随机休眠100到500毫秒来模拟耗时任务,并返回任务花费的时间,在UI线程上调用这个方法会造成阻塞,导致UI假死,因此需要通过异步方式执行这个任务,并在信息输出区域显示花费的时间。

主界面中通过各种不同按钮测试不同类型的异步操作

0x02 使用Thread进行异步操作
使用ThreadPool进行异步操作的方法如下所示,需要注意的就是IsBackground默认为false,也就是该线程对调用它的线程不产生依赖,当调用线程退出时该线程也不会结束。因此需要将IsBackground设置为true以指明该线程是后台线程,这样当主线程退出时该线程也会结束。另外跨线程操作UI还是要借助Dispatcher.BeginInvoke(),如果需要阻塞UI线程可以使用Dispatcher.Invoke()。

0x03 使用ThreadPool进行异步操作
ThreadPool(线程池)的出现主要就是为了提高线程的复用(类似的还有访问数据库的连接池)。线程的创建是开销比较大的行为,为了达到较好的交互体验,开发中可能会大量使用异步操作,特别是需要频繁进行大量的短时间的异步操作时,频繁创建和销毁线程会在造成很多资源的浪费。而通过在线程池中存放一些线程,当需要新建线程执行操作时就从线程池中取出一个已经存在的空闲线程使用,如果此时没有空闲线程,且线程池中的线程数未达到线程池上限,则新建一个线程,使用完成后再放回到线程池中。这样可以极大程度上省去线程创建的开销。线程池中线程的最小和最大数都可以指定,不过多数情况下无需指定,CLR有一套管理线程池的策略。ThreadPool的使用非常简单,代码如下所示。跨线程操作UI仍需借助Dispatcher。

0x04 使用Task进行异步操作
Task进行异步操作时也是从线程池中获取线程进行操作,不过支持的操作更加丰富一些。而且Task<T>可以支持返回值,通过Task的ContinueWith()可以在Task执行结束后将返回值传入以进行操作,但在ContinueWith中跨线程操作UI仍需借助Dispatcher。另外Task也可以直接使用静态方法Task.Run<T>()执行异步操作。

0x05 使用async/await进行异步操作
这个是C#5中的新特性,当遇到await时,会从线程池中取出一个线程异步执行await等待的操作,然后方法立即返回。等异步操作结束后回到await所在的地方接着往后执行。await需要等待async Task<T>类型的函数。详细的使用方法可参考相关资料,测试代码如下所示。异步结束后的会返回到调用线程,所以修改UI不需要Dispatcher。

也可以把TestTask包装成async方法,这样就可以使用上图中注释掉的两行代码进行处理。包装后的异步方法如下所示:

async/await也是从线程池中取线程,可实现线程复用,而且代码简洁容易阅读,异步操作返回后会自动返回调用线程,是执行异步操作的首选方式。而且虽然是C#5的新特性,但C#4可以通过下载升级包来支持async/await。
0x06 关于效率
以上尝试的方法除了直接使用Thread之外,其他几种都是直接或间接使用线程池来获取线程的。从理论上来分析,创建线程时要给线程分配栈空间,线程销毁时需要回收内存,创建线程也会增加CPU的工作。因此可以连续创建线程并记录消耗的时间来测试性能。测试代码如下所示:

当测试Thread时每次测试在连续创建线程时内存和CPU都会有个小突起,不过在线程结束后很快就会降下去,在我的电脑上连续创建100个线程大概花费120-130毫秒。如图所示:

测试结果:

使用基于线程池的方法创建线程时,有时第一次会稍慢一些,应该是线程池内线程不足,时间开销在0-15毫秒,第一次创建内存也会上升。后面再测试时时间开销为0毫秒,内存表现也很平稳,CPU开销分布比较平均。测试结果如图所示:

0x07 结论
在执行异步操作时应使用基于线程池的操作,从代码的简洁程度和可读性上优先使用async/await方式。对于较老的.NET版本可以使用Task或ThreadPool。符合以下情况的可以使用Thread:
1、线程创建后需要持续工作到主线程退出的。这种情况下就算使用线程池线程也不会归还,实现不了复用,可以使用Thread。
2、线程在主线程退出后仍需要执行的,这种情况使用线程池线程无法满足需求,需要使用Thread并制定IsBackground为false(默认)。
0x08 相关下载
测试程序代码在:https://github.com/durow/TestArea/tree/master/AsyncTest/AsyncTest
使用Task异步执行方法_多线程_应用程序池的更多相关文章
- .Net Task 异步执行不等待结果返回
该文章适合有一定异步编程基础的童鞋 开始之前先看.NET官网的一张图: 异步编程中最需弄清的是控制流是如何从方法移动到方法的. 没有理解的话可以去看一下 https://docs.microsoft. ...
- 使用spring的@Async异步执行方法
应用场景: 1.某些耗时较长的而用户不需要等待该方法的处理结果 2.某些耗时较长的方法,后面的程序不需要用到这个方法的处理结果时 在spring的配置文件中加入对异步执行的支持 <beans x ...
- 使用SpringMVC @Async异步执行方法的笔记 (转载)
原文:http://blog.csdn.net/yuwenruli/article/details/8514393 测试代码: @RunWith(SpringJUnit4ClassRunner.cla ...
- Spring Boot 之异步执行方法
前言: 最近的时候遇到一个需求,就是当服务器接到请求并不需要任务执行完成才返回结果,可以立即返回结果,让任务异步的去执行.开始考虑是直接启一个新的线程去执行任务或者把任务提交到一个线程池去执行,这两种 ...
- 【转】WPF 异步执行方法后对 UI 进行更新的几种方法
使用 async/await 的情况: private async void Button_Click(object sender, RoutedEventArgs e) { (sender as B ...
- springboot学习入门简易版七---springboot2.0使用@Async异步执行方法(17)
1启动类开启异步调用注解 @SpringBootApplication @EnableAsync //开启异步调用 public class StartApplication { 不开启则异步调用无效 ...
- SpringBoot-@async异步执行方法
启动加上@EnableAsync ,需要执行异步方法上加入 @Async 在方法上加上@Async之后 底层使用多线程技术 演示代码: @RestController @Slf4j public c ...
- 新手浅谈Task异步编程和Thread多线程编程
初学Task的时候上网搜索,看到很多文章的标题都是task取代thread等等相关,我也一直以为task和thread是一类,其实task是.net4.0提出的异步编程,在之前.net1.0有dele ...
- C#.NET使用Task,await,async,异步执行控件耗时事件(event),不阻塞UI线程和不跨线程执行UI更新,以及其他方式比较
使用Task,await,async,异步执行事件(event),不阻塞UI线程和不跨线程执行UI更新 使用Task,await,async 的异步模式 去执行事件(event) 解决不阻塞UI线程和 ...
随机推荐
- Ubuntu安装pyenv实现python多版本控制
Ubuntu安装pyenv实现python多版本控制 git clone git://github.com/yyuu/pyenv.git ~/.pyenv echo 'export PYENV_ROO ...
- 有哪些知名的公司在用Python
谷歌:Google App Engine.code.Google.com.Google earth.谷歌爬虫.Google广告等项目都在大量使用Python开发 CIA:美国中情局网站就是用Pytho ...
- 你不知道的 #include
1.#include 指令 C++的程序中带 “#” 号的语句被称为宏定义或编译指令.#include在代码中是包含和引用的意思,例如:"#include <iostream>& ...
- 03 of learning python
01 input输入的是str类型 如果输入的是数字的话,要记得强制转换一下! 02 isdigit() 这个方法是用来检测字符串是否全部由数字组成 str.isdigit() 如果字符串只包含数字则 ...
- Python在Windows上安装配置测试
Python是跨平台的,它可以运行在Windows.Mac和各种Linux/Unix系统上.在Windows上写Python程序,放到Linux上也是能够运行的. 2.x还是3.x 目前,Python ...
- Python之旅Day5 列表生成式 生成器 迭代器 装饰器
装饰器 器即函数,装饰即修饰,意指为其他函数添加新功能 装饰器定义:本质就是函数,功能是为其他函数添加新功能 装饰器涉及的知识点= 高阶函数+函数嵌套+闭包 在遵循下面两个原则的前提下为被装饰者新功能 ...
- 实现一个simple 3层的神经网络
1.基本概念 1.1softmax softmax函数:一句话概括:是logistic 函数的扩展,将一个p维的数值向量映射成为一个k维的概率值,且这k个值的和为1. 公式: 解释: 1.2 cros ...
- linux 解决乱码问题
乱码分两种情况: 1.终端(纯 shell 界面)的乱码 vi /etc/profile export LC_ALL="zh_CN.GB18030:zh_CN.GB2312:zh_CN.G ...
- Java工程师如何在1个月内做好面试准备?
作者:石杉的架构笔记 写在前面 春节长假转眼已过,即将迎来的是一年一度的金三银四跳槽季. 假如你准备在金三银四跳槽的话,那么作为一个Java工程师,应该如何利用1个月的时间,快速的为即将到来的面试进行 ...
- Kali学习笔记12:服务扫描
关于什么是服务扫描不多介绍,通俗来看: 我已经扫描到目标机器某个端口开放,接下来我需要知道开放这个端口的是什么应用 情景: 我的Kali机器IP地址:192.168.22.130 我要扫描的Metas ...