asp.net

位置:IT落伍者 >> asp.net >> 浏览文章

ASP.NET使用多线程范例


发布日期:2020年11月27日
 
ASP.NET使用多线程范例

Web开发中使用多线程可以增强用户体验尤其是多用户多任务海量数据和资源紧张的情况下下面这些代码范例都是入门级的希望对对大家学习ASPNet多线程编程有所帮助

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

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

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

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

假设第二个查询语句如SELECT * FROM Category

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

public classBindData

{

private int currentPage = ;

private Repeater rpID;

public BindData(Repeater rpID)

{

thisrpID = rpID;

}

public BindData(Repeater rpIDint page)

{

thisrpID = rpID;

thiscurrentPage = page;

}

public void BindCategory()

{

string strSql=SELECT * FROM Category;

thisBindDataToRepeater(strSql thisrpID);

}

public void BindArchive()

{

string strSql = stringFormat(SELECT * FROM Archives WHERE Page={}thiscurrentPage);

thisBindDataToRepeater(strSql thisrpID);

}

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

{

connOpen();

dtr = cmdExecuteReader();

controlIDDataSource = rp;

controlIDDataBind();

if (!dtrIsClosed)

dtrClose();

}

catch { }

finally

{

cmdDispose();

if (connState = ConnectionStateOpen)

connClose();

}

}

}

上面创建的BindData类中有个构造函数分别用于绑定分类绑定Arhive的不同形式如果使用其他数据绑定控件则可进行相应修改

创建了个私有方法BindDataToRepeater用于把对应的SQL语句查询的结果绑定到对应的Repeater控件上同时在此方法中使用了SqlDataReader以提高绑定数据的速度如果你使用了数据工厂可修改BindDataToRepeater中的具体实现过程

个共有方法BindCategory和BindArchive分别用于创建不同SQL语句设置Repater的ID

同时需要引入SystemWebUISystemWebUIHtmlControlsSystemDataSqlClient个必要的命名空间

值得注意的是在BindDataToRepeater方法中使用了trycatch语句但并没有在catch块中做任何事情为什么我们用trycatch却不在catch块中做点什么事情呢不是多此一举吗?使用trycatch是为了防止在执行BindDataToRepeater时抛出异常若此处出现异常且此方法是在多线程中执行的将会导致IIS进程崩溃进而影响其他页面的正常执行故而用trycatch防止BindDataToRepeater抛出错误

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

public classBindData

{

private int currentPage = ;

private Repeater rpID;

public BindData(Repeater rpID)

{

thisrpID = rpID;

}

public BindData(Repeater rpIDint page)

{

thisrpID = rpID;

thiscurrentPage = page;

}

public void BindCategory()

{

string strSql=SELECT * FROM Category;

thisBindDataToRepeater(strSql thisrpID);

}

public void BindArchive()

{

string strSql = stringFormat(SELECT * FROM Archives WHERE Page={}thiscurrentPage);

thisBindDataToRepeater(strSql thisrpID);

}

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

{

connOpen();

dtr = cmdExecuteReader();

controlIDDataSource = rp;

controlIDDataBind();

if (!dtrIsClosed)

dtrClose();

}

catch { }

finally

{

cmdDispose();

if (connState = ConnectionStateOpen)

connClose();

}

}

}

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

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

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

上一篇:过滤ASP.NET输出HTML中的无用空格

下一篇:ASP.NET数据绑定—多样的绑定方式