Welcome 微信登录

首页 / 网页编程 / ASP.NET / 浅谈.NET下的多线程和并行计算(十四)并行计算前言

浅谈.NET下的多线程和并行计算(十四)并行计算前言2011-08-03 博客园 lovecindywang之前的文章中我们介绍了如何在.NET下运用相关类库进行多线程编程的基础,我们知道.NET 4.0已经 正式推出了,带来的重要特性是并行库。本文就谈谈对并行计算的一些理解和看法。并行计算不是一个很 新的概念,其实它就是通过多线程把同一个任务分割成多个子任务并行的执行的过程。.NET 4.0并行库不 但提供了这方面的支持,而且还封装了多线程开发的各种场景,使得我们不需要依赖Thread/同步基元等 “底层”的对象就可以进行多线程开发。没有.NET 4.0的并行计算库我们同样可以进行并行计算,只不过 我们需要手动分割任务所依赖的数据结构和算法,放到不同的线程中去,然后再使用线程同步的方法来统 一汇总和处理这些线程的执行结果。之所以会需要并行计算是因为随着我们电脑的CPU不在是升级频率而 是横向扩展核心,我们的程序也就达不到随着CPU的Scale-out而Scale-up的能力,因此,需要调整程序的 逻辑使得一段原本不分割的任务也分割成多个片段同时执行,这样就可以利用到多个核心从而提供程序的 性能。

微软每一次推出一个新的框架都会有很多宣传,但我们并没有从这些宣传中看到一些建议,在什么时 候我们不应该去使用这个框架。在Linq to sql推出之后,很多人开始使用并放弃了存储过程,但在使用 的时候毫不关心背后框架做了什么,因为微软的东西实在是太容易使用了,不了解ORM的人可以很方便的 学会使用Linq to sql:

1) 随便把数据库访问包在循环中,或者是GridView类似控件的ItemDataBound类似循环触发事件的方 法中进行数据库访问操作,导致一个页面上百个上千个数据库连接,在以前使用存储过程的时候谁也不会 这么干。

2) 即使读取一个字段一条记录也把所有字段,以及行所关联的字表的数千行记录都取出来。

这就导致Linq to sql变成一个危险的产品,因为在没有使用前,古老的方式让大家都不会犯错误,一 旦变成自动化了,大家就很容易犯错误。其实我想说的是.NET 4.0的并行框架也可能会这样,为什么这样 说呢? 其实,对于一个Windows应用程序的程序员来说,即使没有.NET 4.0并行库,他们也非常清楚怎么 去使用线程,进行多线程的编程,.NET 4.0并行库的到来只是简化了多线程编程方式,以及让我们更容易 进行并行计算。我想说的是,如果程序需要优化需要利用多核的话,在并行库到来之前他也就这么干了。 但对于ASP.NET程序员来说就不一样了,很多ASP.NET程序员在.NET 4.0并行库或并行计算这个词出现之前 没接触过多线程开发,也很少在网站中直接去使用线程,看到.NET 4.0并行库之后很容易以为这是提高性 能的一个良方。而且也确实很容易使用,我们只要加几行代码就可以让我们的循环遍历变成一个并行的行 为,就可以让我们的同一个方法内的不同代码段在多个线程中并行执行。

其实,对于ASP.NET程序来说这种做法不一定能提高性能,可能会降低性能,甚至会导致网站瘫痪,很 可能会造成很多莫名其妙的BUG。主要原因有两点:

1) 之前没有多线程背景,由于太容易使用了,盲目把程序改造成并行程序,但看不到其中潜在的问 题。

2) WEB程序本身就是处于一个多线程环境中的,和Windows程序不一样,我们的用户不是一个,我们 的程序已经由WEB服务器的线程池中的若干线程同时执行了。换一句话说,WEB应用程序即使一个页面从头 到尾从处理UI到读取数据到格式化UI只是一个线程的话,我们同样能充分利用CPU资源,利用到多核,因 为操作系统会把不同的线程调度到不同的核上去。

现在就这两点问题进行一下展开,首先是并行计算(多线程)会有哪些潜在问题?

1) 多个线程共享相同的内存分配,很典型的对值进行累加,如果多个线程同时访问的话累加还准确 吗?

2) 过多的线程,即使不存在共享内存,对于一百个一个短时间的操作使用一百个新线程执行的话最 终运行的时间很可能大于在一个线程中循环顺序执行这个操作一百次。

3) 即使我们自己的程序是线程安全的,在多线程环境下调用.NET类库或其它类库的方法是不是线程 安全的?即使是线程安全的,我们还要意识到一点,如果它本来就采用锁方式确保线程安全的话即使我们 多线程去调用这个方法也不能带来性能的提升。

4) 多线程操作UI的问题。

5) 互相等待或死锁的问题。

6) 调试/平台适应等问题。