ASP.NET 多线程 监控任务执行情况,并显示进度条
关于多线程的基本概念和知识在本文中不多讲,而且我懂的也不是很透,说的太多误人子弟...对于我来说,做本文提到的功能够用就行,等实现其他效果不够用的时候,再深入研究
推荐看园子里的两篇博客应该就有个基本的认识了:
C#多线程(一):http://www.cnblogs.com/oshyn/p/3628686.html
C#多线程(二):http://www.cnblogs.com/oshyn/p/3628792.html
有时候我们在执行一个较长任务的时候,浏览器就好比处于“挂起”的状态,你得等待他把这一个事情处理完毕再去处理其他事情。
那么比如说我们在执行一个反复插入数据库的操作,或者说执行大量的IO的操作的时候,这个过程往往是很耗时的,浏览器长时间不响应,对于客户的忍耐度是一个挑战。
就好像你在安装游戏,只有一段文字提示你“正在安装,请稍后...”结果稍后了半个小时还在稍后,我不知道还要稍后多久,那我简直要疯了。
所以这时候,如果能实时显示当前安装包正在做什么,复制什么文件,执行什么操作,已完成了多少,还剩下多少。这样的话,果然是极好的......
以前也知道做这个功能的时候需要用到多线程来执行,基本道理和思路也懂,但是觉得多线程太麻烦,也不利于管理,因此很傻很天真地想了一个变相解决方案。
基本想法是这样的:
在执行任务的页面上放上两段JS代码,分别是: dowork() checkstate()。其中,dowork() 以ajax方式提交请求,执行耗时长的操作,在操作过程中,不断把执行信息写入Session,而checkstate()以ajax的方式提交请求,执行获取session信息,接收到响应之后,写入div中显示出来。
然而事实上是,在执行操作过程中,确实把任务信息写入了session,但是在dowork()请求的任务执行完毕之前,checkstate()请求的 读取session的操作是不会执行的,在dowork请求的任务执行完毕之后,checkstate()才会把最终的session值获取到。
虽然知道可能是关于单线程的任务执行顺序问题,但是具体说不出来个门道(有哪位行家给分析分析。。。。。不胜感谢~)
后来就只能做多线程来实现了,不多废话,直接上代码,注释写的都很详细
主要分为两个页面 一个任务执行页面(Default) ,放置的按钮和信息呈现的容器,另一个页面是ajax请求页面(ajaxWork),用来执行请求操作和返回响应信息。
<div>
多线程监测任务执行情况示例
<br /><br />
<div class="msg"><div class="msg2"></div></div><br />
<input type="button" onclick="create('');" value="开始执行" />
<span></span>
</div>
Default.aspx
function create(value) //写一个点击执行的函数,点击请求时,实参为空
{
var url="ajaxwork.aspx"; //初始化请求地址 if(value!="") //判断如果实参不为空,则带参请求
{
url+="?key="+value
} $.post(url,function(data)
{
var rs = new Function("return" + data)(); //转换JSON数据 $("span").html("用时:"+rs.time+" 已完成:"+rs.curr+"%"); //输出当前任务执行情况 $(".msg2").css("width",rs.curr+"%"); // 控制进度条的加载 if(rs.curr!="100") //判断如果没有查到100 则递归执行本方法
{
create("1"); //带参请求(参数是多少无所谓,有就行),获取任务执行状态
}
});
}
页面脚本
using System;
using System.Threading; public partial class AjaxWork : System.Web.UI.Page
{
static string count = "";
protected void Page_Load(object sender, EventArgs e)
{
if (Request.QueryString["key"] == null) //判断如果为空 则为第一次请求 启动所要执行的任务
{
Start();
}
else //否则为请求任务执行的状态
{
ajaxResponse();
}
} /// <summary>
/// 线程所要执行的查数方法
/// </summary>
private void DoWork()
{
count = "{'curr':'0','time':'00:00:00.0000000'}";//每次执行操作之前 初始化信息
DateTime starttime = DateTime.Now; //获取任务开始的时间
for (int i = ; i < ; i++) //从1查数到100
{
Thread.Sleep(); // 为了不让程序一下执行完毕,设置线程的休眠,方便演示
count = "{'curr':'" + i.ToString() + "','time':'" +(DateTime.Now - starttime) + "'}"; //反馈当前任务状态
}
} /// <summary>
/// 线程启动
/// </summary>
private void Start()
{
Thread t = new Thread(DoWork); //实例化一个线程
t.Start(); //启动
Response.Write("{'curr':'0','time':'00:00:00.0000000'}"); //第一次请求返回初始化的信息
} /// <summary>
/// 获取任务的实时信息
/// </summary>
private void ajaxResponse()
{
Response.Write(count);
Response.Flush();
Response.End();
}
}
ajaxWork.aspx.cs
效果如下图:

Demo下载:http://files.cnblogs.com/webconfig/Thread.rar
==============================华丽的分割线==================================
另外一个问题是,不知道为什么,在ajaxWork.aspx.cs中 声明的
static string count = ""
如果你在每次执行线程的时候不进行初始化操作

那么,你在第一次执行的时候,是正常的。但是,第一次执行完成之后,再次点按钮的时候,就会出现“抽筋”情况,具体可以下载demo看效果、
断电调试,可以发现,第二次执行,count初始化的值,不是“”,而是第一次执行完毕之后的值:

哪位高手给解释一下...
忽然想到了生命周期的问题,原来一直以为,静态变量的生命周期是随着类的消亡而消亡的,对于ASP.NET,好像不是这样,看到一篇文章上提到,静态变量是application级别的,也就是说除非IIS重启,否则静态变量的值就是最后修改的值...也许可以解释这个问题吧
文章地址:http://www.cnblogs.com/webconfig/p/3632260.html
---- 内容补充 -------------------------------------------------------------------------------
今天下午有稍微研究了一下,也感谢@AllEmpty提出的观点,用静态变量传值确实会引发并发问题,当时为了图省事直接用静态变量传值了。后来想过用session传值,可是在新开辟的线程中使用session 总是引发异常,异常提示为:

今天下午终于找到原因了,那就是在新开辟的线程使用session之前,需要在主线程中声明出session,否则就会引起该异常。
所以我们修改代码:
1,声明的静态变量count去掉,在线程启动之前在主线程声明出session
if (Request.QueryString["key"] == null) //判断如果为空 则为第一次请求 启动所要执行的任务
{
Session["count"] = "";
Start();
}
2,使用session记录状态:
private void DoWork()
{
Session["count"] = "{'curr':'0','time':'00:00:00.0000000'}";//每次执行操作之前 初始化信息
DateTime starttime = DateTime.Now; //获取任务开始的时间
for (int i = ; i < ; i++) //从1查数到100
{
Thread.Sleep(); // 为了不让程序一下执行完毕,设置线程的休眠,方便演示
Session["count"] = "{'curr':'" + i.ToString() + "','time':'" + (DateTime.Now - starttime) + "'}"; //反馈当前任务状态
}
}
3,响应session的值
string countstr = "";
if (Session["count"] != null)
{
countstr = Session["count"].ToString();
}
Response.Write(countstr);
OK,并发问题解决!!!
本文出自博客园:D调的码农
转载请注明出处:http://www.cnblogs.com/webconfig/p/3632208.html
ASP.NET 多线程 监控任务执行情况,并显示进度条的更多相关文章
- (委托事件处理)关于多线程执行显示进度条的实例(转)&&线程间操作无效: 从不是创建控件“rtxtEntryNO”的线程访问它。
关于多线程执行显示进度条的实例! 之前回答了一篇关于怎么在线程中操作进度条的帖子,估计有人看的不是很明白今天没事,写了一个小小的实例,很简单,就2个文件权当抛砖引玉,希望有更好解决方案的人发表一下意见 ...
- Asp.Net实现无刷新文件上传并显示进度条(非服务器控件实现)(转)
Asp.Net实现无刷新文件上传并显示进度条(非服务器控件实现) 相信通过Asp.Net的服务器控件上传文件在简单不过了,通过AjaxToolkit控件实现上传进度也不是什么难事,为什么还要自己辛辛苦 ...
- Asp.net mvc 大文件上传 断点续传 进度条
概述 项目中需要一个上传200M-500M的文件大小的功能,需要断点续传.上传性能稳定.突破asp.net上传限制.一开始看到51CTO上的这篇文章,此方法确实很不错,能够稳定的上传大文件,http: ...
- C#调用耗时函数时显示进度条浅探
最近在做一个VSS日志分析工具,使用C#进行开发,在完成了所有功能后,发现,从服务器下载VSS日志非常耗时,因为此,导致工具使用体验不好,所以,准备增加一个进度条.鉴于C#不经常使用,一下子搞个进度条 ...
- android标题栏(titlebar)显示进度条
在后台线程中执行各种操作(网络连接.大数据存储)的时候,我们希望让客户能看到后台有操作在进行,那么既能有效的提示用户,又不占用当前操作空间,最好的方法就是在标题栏有个进度条. [代码] [Java]代 ...
- C# WinFrom 导入Excel文件,显示进度条
因为WINForm程序是在64位上运行如果使用另外一种快速的读取Excel的方法会报“未在本地计算机上注册“Microsoft.Jet.OLEDB.12.0”提供程序” 所以我就换了现在这种读取有点慢 ...
- easyui datagrid显示进度条控制操作
在当我们需要控制时间前台实际项目页面datagrid显示进度条的数据加载时运行,和datagrid默认情况下只在有url加载运行时的数据显示方式的进度条.下面的代码手动控制: 打开一个进度条: $(' ...
- 利用Python计算π的值,并显示进度条
利用Python计算π的值,并显示进度条 第一步:下载tqdm 第二步;编写代码 from math import * from tqdm import tqdm from time import ...
- 【转】C#中使用aria2c进行下载并显示进度条
[转自] C#中使用aria2c进行下载并显示进度条 - 云平台知识库 - 博客园https://www.cnblogs.com/littlehb/p/5782714.html 正则表达式的生成网站: ...
随机推荐
- javascript design patterns
http://jsdesignpatterns.com/ http://www.joezimjs.com/tag/design-patterns/ http://codecube.net/#archi ...
- Hibernate中的事务隔离
在我们的项目中,老发现程序报告sesssion is closed或者因数据已经被其他事务修改而导致当前事务无法提交,由于系统的运行用户最多也就几十个人,所以考虑使用严格的事务隔离来防止这种类型的问题 ...
- Struts2 权限验证
之前的Struts2项目通过再Sitemesh的母版页中使用Struts的if标签进行了session判断,使得未登录的用户不能看到页面,但是这 种现仅仅在view层进行,如果未登录用户直接在地址栏输 ...
- adb测试使用相关
1.adb中文 无论是shell下显示中文.logcat输出中文乱码还是adb push/pull路径包括中文名,windows下都可以通过更改cmd窗口代码页为UTF-8解决: chcp 65001 ...
- 如何让自己的类用 copy 修饰符?如何重写带 copy 关键字的 setter?
出题者简介: 孙源(sunnyxx),目前就职于百度 整理者简介:陈奕龙,目前就职于滴滴出行. 转载者:豆电雨(starain)微信:doudianyu 若想令自己所写的对象具有拷贝功能,则需实现 N ...
- Java调用R(三)_系统命令调用
java通过配置的系统命令Rscript直接调用R脚本. 优点:R脚本和Java代码完全分离 缺点:R中变量不能控制 1. Java本地能够成功调用. public void CallR() { Ru ...
- mybatis处理单表多表操作以及动态sql和批量操作
一.单表操作 建立了相应的mapper映射接口类后,在src/main/resources目录下的自己建立的mapper文件夹下创建映射类 select操作:用select标签 属性id为映射接口的方 ...
- sql给整数补零
update hs_user.clientorder a set a.stockcode = lpad(a.stockcode,6,'0') where a.market = 'SZ'
- mac上charels抓包工具使用技巧
有这俩技巧就足够了 http://www.jianshu.com/p/18449f5f9d1c http://blog.csdn.net/u010187139/article/details/5198 ...
- 三星 note3销售地查询、销售地代码
查看销售地代码 用KIES验销售地:记下设定-关于-状态里的序号. 手机不要连接电脑,注意是不要连接,打开KIES3,点工具——固件恢复和初始化,输入大写的型号SM-N900或者SM-N9005,确认 ...