首页 > 编程 > .NET > 正文

asp.net利用多线程执行长时间的任务,客户端显示出任务的执行进度的示例

2024-07-10 13:05:57
字体:
来源:转载
供稿:网友

对上一次的做一点修改,增加一个比较美观的进度显示

0%20&&%20image.height>0){if(image.width>=510){this.width=510;this.height=image.height*510/image.width;}}"%20border=0>%20
上面那个是运行中的画面,下面那个是结束后的画面%20
0%20&&%20image.height>0){if(image.width>=510){this.width=510;this.height=image.height*510/image.width;}}"%20border=0>%20
用到的图标在这里:0%20&&%20image.height>0){if(image.width>=510){this.width=510;this.height=image.height*510/image.width;}}"%20border=0>%20

对上次的前台修改如下:%20

<%@%20page%20language="c#"%20codebehind="webform54.aspx.cs"%20autoeventwireup="false"%20inherits="csdn.webform54"%20%>%20
<!doctype%20html%20public%20"-//w3c//dtd%20html%204.0%20transitional//en"%20>%20
<html>%20
 <head>%20
  <title>webform54</title>%20
  <meta%20content="microsoft%20visual%20studio%20.net%207.1"%20name="generator">%20
  <meta%20content="c#"%20name="code_language">%20
  <meta%20content="javascript"%20name="vs_defaultclientscript">%20
  <meta%20content="
http://schemas.microsoft.com/intellisense/ie5"%20name="vs_targetschema">%20
  <style%20type="text/css">%20
  .font%20{%20font-weight:%20normal;%20font-size:%209pt;%20color:%20#000000;%20font-family:%20"宋体",%20sans-serif;%20background-color:%20#f0f0f0;%20text-decoration:%20none%20}%20
  </style>%20
 </head>%20
 <body>%20
  <form%20id="form1"%20method="post"%20runat="server">%20
   <div%20id="div_load"%20runat="server">%20
    <table%20width="320"%20height="72"%20border="1"%20bordercolor="#cccccc"%20cellpadding="5"%20cellspacing="1"%20
     class="font"%20>%20
     <tr>%20
      <td>%20
       <p><img%20alt="请等待"%20src="http://www.pushad.com/info/clocks.gif" align="left">
        <br>
        <asp:label id="lab_state" runat="server"></asp:label></p>
      </td>
     </tr>
    </table>
    <br>
   </div>
   <asp:button id="btn_startwork" runat="server" text="运行一个长时间的任务"></asp:button><br>
   <br>
   <asp:label id="lab_jg" runat="server"></asp:label>
  </form>
 </body>
</html>

后台修改如下:

using system;
using system.collections;
using system.componentmodel;
using system.data;
using system.data.sqlclient;
using system.drawing;
using system.web;
using system.web.sessionstate;
using system.web.ui;
using system.web.ui.webcontrols;
using system.web.ui.htmlcontrols;

namespace csdn
{
 /// <summary>
 /// webform54 的摘要说明。
 /// </summary>
 public class webform54 : system.web.ui.page
 {
  protected system.web.ui.htmlcontrols.htmlgenericcontrol div_load;
  protected system.web.ui.webcontrols.button btn_startwork;
  protected system.web.ui.webcontrols.label lab_state;
  protected system.web.ui.webcontrols.label lab_jg;
  protected work w;

  private void page_load(object sender, system.eventargs e)
  {
   // 在此处放置用户代码以初始化页面
   if(session["work"]==null)
   {
    w=new work();
    session["work"]=w;
   }
   else
   {
    w=(work)session["work"];
   }
   switch(w.state)
   {
    case 0:
    {
     this.div_load.visible=false;
     break;
    }
    case 1:
    {
     this.lab_state.text=""+((timespan)(datetime.now-w.starttime)).totalseconds.tostring("0.00")+" 秒过去了,完成百分比:"+w.percent+" %";
     this.btn_startwork.enabled=false;
     page.registerstartupscript("","<script>window.settimeout('location.href=location.href',1000);</script>");
     this.lab_jg.text="";
     break;
    }
    case 2:
    {
     this.lab_jg.text="任务结束,并且成功执行所有操作,用时 "+((timespan)(w.finishtime-w.starttime)).totalseconds+" 秒";
     this.btn_startwork.enabled=true;
     this.div_load.visible=false;
     break;
    }
    case 3:
    {
     this.lab_jg.text="任务结束,在"+((timespan)(w.errortime-w.starttime)).totalseconds+"秒的时候发生错误导致任务失败'";
     this.btn_startwork.enabled=true;
     this.div_load.visible=false;
     break;
    }
   }
  }

  #region web 窗体设计器生成的代码
  override protected void oninit(eventargs e)
  {
   //
   // codegen: 该调用是 asp.net web 窗体设计器所必需的。
   //
   initializecomponent();
   base.oninit(e);
  }
  
  /// <summary>
  /// 设计器支持所需的方法 - 不要使用代码编辑器修改
  /// 此方法的内容。
  /// </summary>
  private void initializecomponent()
  {   
   this.btn_startwork.click += new system.eventhandler(this.btn_startwork_click);
   this.load += new system.eventhandler(this.page_load);

  }
  #endregion

  private void btn_startwork_click(object sender, system.eventargs e)
  {
   if(w.state!=1)
   {
    this.btn_startwork.enabled=false;
    this.div_load.visible=true;
    w.runwork();
    page.registerstartupscript("","<script>location.href=location.href;</script>");
            
   }
  }
 }

 public class work
 {
  public int state=0;//0-没有开始,1-正在运行,2-成功结束,3-失败结束
  public int percent=0;//完成百分比
  public datetime starttime;
  public datetime finishtime;
  public datetime errortime;

  public void runwork()
  {
   lock(this)
   {
    if(state!=1)
    {
     state=1;
     starttime=datetime.now;
     system.threading.thread thread=new system.threading.thread(new system.threading.threadstart(dowork));
     thread.start();                        
    }
   }
  }

  private void dowork()
  {
   try
   {
    sqlconnection conn=new sqlconnection(system.configuration.configurationsettings.appsettings["conn"]);
    sqlcommand cmd=new sqlcommand("insert into test (test)values('test')",conn);
    conn.open();
    for(int p=0;p<100;p++)
    {
     for(int i=0;i<10;i++)
     {
      cmd.executenonquery();
     }
     percent=p;//这里就是定义百分比,你估计这个操作费多少时间定义多少百分比
    }
    conn.close();
    //以上代码执行一个比较消耗时间的数据库操作
    state=2;
   }
   catch
   {
    errortime=datetime.now;
    percent=0;
    state=3;
   }
   finally
   {
    finishtime=datetime.now;
    percent=0;
   }
  }
 }
}

 在asp.net中执行一个长时间的操作,有的时候需要在在客户端有一个反馈能了解到任务的执行进度,大致看了一下有这么几种做法:
(1)按下按钮的时候给出一个<div>提示正在执行任务,执行完毕让这个<div>隐藏
(2)按下按钮的时候跳转到一个提示任务正在执行的页面,执行完毕了再跳转回来
(3)做一个任务类,开启另外一个线程执行任务,同时在客户端或者服务器端保存这个类的实例来跟踪任务的执行情况
(1)和(2)的情况用的比较多,也比较简单,缺点是不能实时的知道任务的执行进度,而且时间一长可能会超时,(3)的方法就会比较好的解决上面说的2个缺点。下面着重说一下(3)的实现方法,先从简单开始,我们做一个任务类,在客户端时时(暂且刷新时间为1秒)得知任务执行了多少时间,并且在成功完成任务后给出执行时间,在任务出错的时候给出出错的时间。
前台
<form id="form1" method="post" runat="server">
<asp:label id="lab_state" runat="server"></asp:label><br>
<asp:button id="btn_startwork" runat="server" text="运行一个长时间的任务"></asp:button>
</form>
后台
先是一些类的申明:
protected system.web.ui.webcontrols.button btn_startwork;
protected system.web.ui.webcontrols.label lab_state;
//前面2个是vs.net自己生成的
protected work w;
在page_load里面输入以下代码:
if(session["work"]==null)
   {
    w=new work();
    session["work"]=w;
   }
   else
   {
    w=(work)session["work"];
   }
   switch(w.state)
   {
    case 0:
    {
     this.lab_state.text="还没有开始任务";
     break;
    }
    case 1:
    {
     this.lab_state.text="任务进行了"+((timespan)(datetime.now-w.starttime)).totalseconds+"秒";
     this.btn_startwork.enabled=false;
     page.registerstartupscript("","<script>window.settimeout(’location.href=location.href’,1000);</script>");
     //不断的刷新本页面,随时更新任务的状态
     break;
    }
    case 2:
    {
     this.lab_state.text="任务结束,并且成功执行所有操作,用时"+((timespan)(w.finishtime-w.starttime)).totalseconds+"秒";
     this.btn_startwork.enabled=true;
     break;
    }
    case 3:
    {
     this.lab_state.text="任务结束,在"+((timespan)(w.errortime-w.starttime)).totalseconds+"秒的时候发生错误导致任务失败";
     this.btn_startwork.enabled=true;
     break;
    }
   }
在按钮单击事件内输入以下代码:
if(w.state!=1)
   {
    this.btn_startwork.enabled=false;
    w.runwork();
    page.registerstartupscript("","<script>location.href=location.href;</script>");
    //立即刷新页面
   }

另外建立一个任务类,代码如下:
public class work
 {
  public int state=0;//0-没有开始,1-正在运行,2-成功结束,3-失败结束
        public datetime starttime;
  public datetime finishtime;
  public datetime errortime;
  public void runwork()
  {
   lock(this)//确保临界区被一个thread所占用
   {
    if(state!=1)
    {
     state=1;
     starttime=datetime.now;
     system.threading.thread thread=new system.threading.thread(new system.threading.threadstart(dowork));
     thread.start();                         
    }
   }
  }
  private void dowork()
  {
   try
   {
    sqlconnection conn=new sqlconnection(system.configuration.configurationsettings.appsettings["conn"]);
    sqlcommand cmd=new sqlcommand("insert into test (test)values(’test’)",conn);
    conn.open();
    for(int i=0;i<5000;i++)cmd.executenonquery();
    conn.close();
    //以上代码执行一个比较消耗时间的数据库操作
    state=2;
   }
   catch
   {
    errortime=datetime.now;
    state=3;
   }
   finally
   {
    finishtime=datetime.now;
   }
  }
 }
}
运行这个页面,看到每秒页面刷新一次反馈任务执行到现在的时间,在结束后给出任务总的用时。(如果任务出错也给出出错时间)
(这个示例比较简单,基本能实现长时间的任务执行与客户端的交互,但是界面不是很友善,而且如果有很多项操作的话,只能给出执行了多少时间,不能显示执行到第几项任务,在下一篇文章中,将会改进这个类和界面)  

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表