博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
ASP.Net教程系列:多线程编程实战(二)
阅读量:5322 次
发布时间:2019-06-14

本文共 4554 字,大约阅读时间需要 15 分钟。

Web开发中使用多线程可以增强用户体验,尤其是多用户、多任务、海量数据和资源紧张的情况下。所以我们的ASP.Net教程设立多线程编程实战专题。下面这些代码范例都是入门级的,希望对对大家学习ASP.Net多线程编程有所帮助。

 

 ASP.Net教程系列:多线程编程实战二之ASP.NET使用多线程范例

 

  使用多线程是为了提高CPU的利用率,即在在相同的时间里面做更多的事情(但前提是系统资源没有完全耗尽),ASP.NET中使用多线程可以加快页面在服务器端的生成速度。一般页面生成过程中花费时间最多的是数据库查询阶段,如果你的页面有10个查询,不使用多线程的话,这10个查询将是串行执行的——即依次执行每一个查询。如果使用多线程,将可以使这10个查询几乎同时执行。这显然会提高页面的生成速度。

在网上搜索了些许帖子说在IIS进程中使用多线程是不稳定的,可我经过实践却发现ASP.NET使用多线程也没出啥问题。不过在ASP.NET中使用多线程得注意一些地方,不然确实是不稳定,甚至是行不通的。比如不能在多线程中使用HttpContext下的任何方法和属性,这就包括Cookie、Session、Response、Request、Application等等,当使用这些方法或者属性的时候,IIS进程将会直接崩溃。更要注意的是,由于多线程与页面的加载(Load)是异步执行的,必须让这些创建的线程在Load执行完之前同步,不然可能导致数据没有加载成功。 可能会有人问HttpContext等都被限制了,页面中还能做什么呢?我们完全可以把创建的线程与页面主体隔开,把需要的数据先在页面主体中获取,然后直接传入到创建的线程中就可解决。话不多说,具体如何,请看下文。

 

  假设某个页面中有2个SQL查询,一个是根据Url传递来的参数P确定当前页的内容,另一个查询是显示所有分类。第一个查询语句需要用到Request.QueryString获取P传递来的页码,第二个查询语句则可直接写SQL语句。

  假设第一个查询语句如:SELECT * FROM Archives WHERE Page=传递的页码
  假设第二个查询语句如:SELECT * FROM Category

  我们先创建一个类,用于接受参数P和数据绑定控件ID(此处使用Repeater控件绑定数据),此类能够把SQL语句查询的结果绑定到数据控件(Repeater)中。

public classBindData
{
    private int currentPage = 1;
    private Repeater rpID;

    public BindData(Repeater rpID)

    {
        this.rpID = rpID;
    }
    public BindData(Repeater rpID,int page)
    {
        this.rpID = rpID;
        this.currentPage = page;
    }  
   

    public void BindCategory()

    {
        string strSql="SELECT * FROM Category";
        this.BindDataToRepeater(strSql, this.rpID);

    }

    public void BindArchive()

    {
        string strSql = string.Format("SELECT * FROM Archives WHERE Page={0}",this.currentPage);
        this.BindDataToRepeater(strSql, this.rpID);
    }

    private void BindDataToRepeater(string strSql, Repeater rp)

    {
        if (rp == null) return;
        SqlConnection conn = new SqlConnection("data source=数据服务器地址;User ID=用户名;pwd=密码;Initial Catalog=数据库名");
        SqlCommand cmd = new SqlCommand(strSql, conn);
        SqlDataReader dtr;
        try

        {

            conn.Open();
            dtr = cmd.ExecuteReader();
            controlID.DataSource = rp;
            controlID.DataBind();
            if (!dtr.IsClosed)
                dtr.Close();
        }
        catch { }
        finally
        {
            cmd.Dispose();
            if (conn.State = ConnectionState.Open)
                conn.Close();
        }
 
    }
}

  上面创建的BindData类中有2个构造函数,分别用于绑定分类、绑定Arhive的不同形式。如果使用其他数据绑定控件则可进行相应修改;
  创建了1个私有方法BindDataToRepeater用于把对应的SQL语句查询的结果绑定到对应的Repeater控件上。同时在此方法中使用了SqlDataReader,以提高绑定数据的速度。如果你使用了数据工厂可修改BindDataToRepeater中的具体实现过程;
  2个共有方法BindCategory和BindArchive分别用于创建不同SQL语句、设置Repater的ID;
同时需要引入System.Web.UI、System.Web.UI.HtmlControls、System.Data.SqlClient3个必要的命名空间。
值得注意的是在BindDataToRepeater方法中使用了try..catch语句,但并没有在catch块中做任何事情,为什么我们用try.catch却不在catch块中做点什么事情呢,不是多此一举吗?使用try..catch是为了防止在执行BindDataToRepeater时抛出异常,若此处出现异常且此方法是在多线程中执行的,将会导致IIS进程崩溃,进而影响其他页面的正常执行,故而用try...catch防止BindDataToRepeater抛出错误。

  我们之所以为数据绑定创建一个类,是为了提高内存利用率,当数据加载(Load)完毕的时候,为这个类创建的实例就会销毁。我们也可以通过在页面中创建几个全局变量来实现。但我还是建议以类的形式传递数据而不是使用全局变量。下面,我们开始在页面的Load中创建线程了。首先你需要在页面中引入System.Threading命名空间。

 

public classBindData
{
    private int currentPage = 1;
    private Repeater rpID;

    public BindData(Repeater rpID)

    {
        this.rpID = rpID;
    }
    public BindData(Repeater rpID,int page)
    {
        this.rpID = rpID;
        this.currentPage = page;
    }  
   

    public void BindCategory()

    {
        string strSql="SELECT * FROM Category";
        this.BindDataToRepeater(strSql, this.rpID);

    }

    public void BindArchive()

    {
        string strSql = string.Format("SELECT * FROM Archives WHERE Page={0}",this.currentPage);
        this.BindDataToRepeater(strSql, this.rpID);
    }

    private void BindDataToRepeater(string strSql, Repeater rp)

    {
        if (rp == null) return;
        SqlConnection conn = new SqlConnection("data source=数据服务器地址;User ID=用户名;pwd=密码;Initial Catalog=数据库名");
        SqlCommand cmd = new SqlCommand(strSql, conn);
        SqlDataReader dtr;
        try

        {

            conn.Open();
            dtr = cmd.ExecuteReader();
            controlID.DataSource = rp;
            controlID.DataBind();
            if (!dtr.IsClosed)
                dtr.Close();
        }
        catch { }
        finally
        {
            cmd.Dispose();
            if (conn.State = ConnectionState.Open)
                conn.Close();
        }
 
    }
}

  上面的代码显示在!IsPostBack状态下绑定数据。利用Request.QueryString获取了当前页码,并创建了BindData的2个实例LoadArchives、LoadCategory,通过 Thread thArhives=new Thread(new ThreadStart(LoadArchives.BindArchive))为绑定Arhice创建线程,通过Thread thCategory = new Thread(new ThreadStart(LoadCategory.BindCategory))为绑定分类创建线程,同时调用Thread的Start方法使2个线程进入执行状态。最后,在Load的最下面用Thread的Join方法使创建的2个线程与页面加载同步。

  值得注意的是,Join方法是必须的,如果不使用,可能导致创建的线程还未把数据完全绑定到Repeater上,Load就已经执行完毕,若如此页面上将没有任何数据。同时调用Start的代码行应尽量早,调用Join的代码行都应尽量迟——尽量放在Page_Load代码段的末尾,这样才能达到多线程的目的,若你每调用一个Start马上调用Join,其实质和没有使用多线程的效果是一样的。Join在MSND上的解释是:在继续执行标准的 COM 和 SendMessage 消息泵处理期间,阻塞调用线程,直到某个线程终止为止。

  只要设置好ASPX页面Repeater的绑定项,数据就可成功加载了。上面仅仅展示了2个SQL语句的查询,如果你有10个或者更多的SQL查询,在Page_Load中创建10个线程,让他们异步执行,最后用Join同步到Load,是一个提高性能的不错方法。

本ASP.Net教程引用来源: http://www.goberl.com/archive/item59.aspx

转载于:https://www.cnblogs.com/elock/archive/2010/04/11/1709630.html

你可能感兴趣的文章
python全栈 计算机硬件管理 —— 硬件
查看>>
大数据学习
查看>>
简单工厂模式
查看>>
Delphi7编译的程序自动中Win32.Induc.a病毒的解决办法
查看>>
Objective-C 【关于导入类(@class 和 #import的区别)】
查看>>
倍福TwinCAT(贝福Beckhoff)常见问题(FAQ)-点击运行按钮进入到运行状态报错Error starting TwinCAT System怎么办 AdsWarning1823怎么办...
查看>>
【转】javascript 中的很多有用的东西
查看>>
Centos7.2正常启动关闭CDH5.16.1
查看>>
Android 监听返回键、HOME键
查看>>
Android ContentProvider的实现
查看>>
sqlserver 各种判断是否存在(表名、函数、存储过程等)
查看>>
给C#学习者的建议 - CLR Via C# 读后感
查看>>
Recover Binary Search Tree
查看>>
Java 实践:生产者与消费者
查看>>
[转]IOCP--Socket IO模型终结篇
查看>>
js 获取视频的第一帧
查看>>
各种正则验证
查看>>
观察者模式(Observer)
查看>>
python中numpy.r_和numpy.c_
查看>>
egret3D与2D混合开发,画布尺寸不一致的问题
查看>>