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),用來執行請求操作和返回響應信息。

 

1 <div>
2     多線程監測任務執行情況示例
3     <br /><br />
4     <div class="msg"><div class="msg2"></div></div><br />
5    <input type="button" onclick="create('');" value="開始執行" />&nbsp;&nbsp;&nbsp;&nbsp;
6    <span></span>
7     </div>
Default.aspx
 1 function create(value) //寫一個點擊執行的函數,點擊請求時,實參為空
 2     {
 3         var url="ajaxwork.aspx"; //初始化請求地址
 4         
 5         if(value!="") //判斷如果實參不為空,則帶參請求
 6         {
 7             url+="?key="+value
 8         }
 9         
10         $.post(url,function(data)
11         {
12             var rs = new Function("return" + data)(); //轉換JSON數據
13             
14             $("span").html("用時:"+rs.time+"&nbsp;&nbsp;&nbsp;&nbsp;已完成:"+rs.curr+"%"); //輸出當前任務執行情況
15             
16             $(".msg2").css("width",rs.curr+"%"); // 控制進度條的加載
17             
18             if(rs.curr!="100") //判斷如果沒有查到100 則遞歸執行本方法
19             {
20                 create("1"); //帶參請求(參數是多少無所謂,有就行),獲取任務執行狀態
21             }
22         });
23     } 
頁面腳本
 1 using System;
 2 using System.Threading;
 3 
 4 public partial class AjaxWork : System.Web.UI.Page
 5 {
 6     static string count = "";
 7     protected void Page_Load(object sender, EventArgs e)
 8     {
 9         if (Request.QueryString["key"] == null) //判斷如果為空 則為第一次請求 啟動所要執行的任務
10         {
11             Start();
12         }
13         else //否則為請求任務執行的狀態
14         {
15             ajaxResponse();
16         }
17     }
18 
19     /// <summary>
20     /// 線程所要執行的查數方法
21     /// </summary>
22     private void DoWork()
23     {
24         count = "{'curr':'0','time':'00:00:00.0000000'}";//每次執行操作之前 初始化信息
25         DateTime starttime = DateTime.Now; //獲取任務開始的時間
26         for (int i = 1; i < 101; i++) //從1查數到100
27         {
28             Thread.Sleep(100); // 為了不讓程序一下執行完畢,設置線程的休眠,方便演示
29             count = "{'curr':'" + i.ToString() + "','time':'" +(DateTime.Now - starttime) + "'}"; //反饋當前任務狀態
30         }
31     }
32 
33     /// <summary>
34     /// 線程啟動
35     /// </summary>
36     private void Start()
37     {
38         Thread t = new Thread(DoWork); //實例化一個線程
39         t.Start(); //啟動
40         Response.Write("{'curr':'0','time':'00:00:00.0000000'}"); //第一次請求返回初始化的信息
41     }
42 
43     /// <summary>
44     /// 獲取任務的實時信息
45     /// </summary>
46     private void ajaxResponse()
47     {
48         Response.Write(count);
49         Response.Flush();
50         Response.End();
51     }
52 }
ajaxWork.aspx.cs

 

效果如下圖:

 

Demo下載:http://files.cnblogs.com/webconfig/Thread.rar 

 

==============================華麗的分割線==================================

 

另外一個問題是,不知道為什么,在ajaxWork.aspx.cs中 聲明的

 1 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記錄狀態:

 1     private void DoWork()
 2     {
 3         Session["count"] = "{'curr':'0','time':'00:00:00.0000000'}";//每次執行操作之前 初始化信息
 4         DateTime starttime = DateTime.Now; //獲取任務開始的時間
 5         for (int i = 1; i < 101; i++) //從1查數到100
 6         {
 7             Thread.Sleep(100); // 為了不讓程序一下執行完畢,設置線程的休眠,方便演示
 8             Session["count"] = "{'curr':'" + i.ToString() + "','time':'" + (DateTime.Now - starttime) + "'}"; //反饋當前任務狀態
 9         }
10     }


3,響應session的值

1         string countstr = "";
2         if (Session["count"] != null)
3         {
4             countstr = Session["count"].ToString();
5         }
6         Response.Write(countstr);

 

OK,並發問題解決!!!

 

 

 

本文出自博客園:D調的碼農

轉載請注明出處:http://www.cnblogs.com/webconfig/p/3632208.html

 

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM