浅谈.NET下的多线程和并行计算(十四)并行计算前言

简介: 之前的文章中我们介绍了如何在.NET下运用相关类库进行多线程编程的基础,我们知道.NET 4.0已经正式推出了,带来的重要特性是并行库。本文就谈谈对并行计算的一些理解和看法。并行计算不是一个很新的概念,其实它就是通过多线程把同一个任务分割成多个子任务并行的执行的过程。

之前的文章中我们介绍了如何在.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) 调试/平台适应等问题。

第二个问题是,ASP.NET 应用程序或说WEB应用程序是否应该使用并行库的问题?

1) 如果我们的操作涉及到IO(磁盘/数据库/网络),操作的时间长并且可以分割,那么我们可以使用多个线程来进行一个大操作,或让多个操作同时执行,加快主线程完成操作的时间。加快时间不但能带来用户体验上的改善,而且能提高系统吞吐,可以想一下,同样的负载,线程池100个工作线程(等IO),100个IO线程好一点还是25个工作线程,100个IO线程好一点?

2) 如果我们的操作很多是CPU绑定的那么要看情况了,如果连接数很高,并且我们的操作都是很短的话,使用并行效果并不会很好,因为我们的CPU没闲着,已经在不断处理任务,线程池也打开了任何线程,再把一个线程能做的事情分成几个线程去做,加大了线程切换的负担,加大了线程池需要使用的线程,加大了系统负担也就减少了吞吐。只有在我们的程序比较复杂并且连接很少(比如是内部的ERP),甚至类似Windows程序的情况下,使用并行才会有好处,增加CPU利用率,提高执行速度。

3) 还要注意一点,我们在开发类库的时候如果知道类库将来的使用群体可能是ASP.NET应用程序,那么我们要慎重考虑是不是需要在类库中引入大量的并行度非常高的操作。

4) 有的时候还是要使用测试数据做依据,不能想当然,比如我们可以想到使用多线程同时下载10个网站的数据会提高效率,那么我们也会理所当然认为使用10个线程访问数据库更新第i*100(i=0-9)条数据会比串行更新1000条数据快一点。但是我们清楚数据库在背后会有什么锁操作吗?

我想说的是,在请求很少甚至只有一两个请求的情况下确实可能会提高速度,但是请求多了谁说的清楚呢,比如在一条不宽的传送带上并行传送我们的行李,分成四堆(四道),如果只有一个人的行李需要传送可能是快一点。但是如果是一千人呢,每个人的行李都铺开传还是每个人的行李都只占用一条道快?难说!对于大量访问的ASP.NET应用程序来说还是慎重点吧,咱一个请求只用一个工作线程一个IO线程够了。

 

不管怎么说,.NET 4.0的并行库给我们提供了工具,怎么去用好它合理使用,还需要根据需求来判断。况且并行库除了之前说了数据并行,任务并行之外,还提供了很多适合多线程环境的集合数据结构(在这之前要实现一个Lock-Free性能优良的适合多线程的数据结构也不是这么简单的事情)。

 

最后引申一下,并行计算是否能不局限于使用CPU,使用GPU呢?http://www.infoq.com/cn/news/2010/05/Brahma

可否把整个方法指令栈和数据栈作为参数传递给多个服务器,让服务器处理完之后返回结果呢?

作者: lovecindywang
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
相关文章
|
27天前
|
Java API 调度
【JavaEE】——多线程(join阻塞,计算,引用,状态)
【JavaEE】——多线程,join,sleep引起的线程阻塞,多线程提升计算效率,如何获取线程的引用和状态
|
6月前
|
Python
解锁Python并发新世界:线程与进程的并行艺术,让你的应用性能翻倍!
【7月更文挑战第9天】并发编程**是同时执行多个任务的技术,提升程序效率。Python的**threading**模块支持多线程,适合IO密集型任务,但受GIL限制。**multiprocessing**模块允许多进程并行,绕过GIL,适用于CPU密集型任务。例如,计算平方和,多线程版本使用`threading`分割工作并同步结果;多进程版本利用`multiprocessing.Pool`分块计算再合并。正确选择能优化应用性能。
45 1
|
2月前
|
开发框架 Java .NET
.net core 非阻塞的异步编程 及 线程调度过程
【11月更文挑战第12天】本文介绍了.NET Core中的非阻塞异步编程,包括其基本概念、实现方式及应用示例。通过`async`和`await`关键字,程序可在等待I/O操作时保持线程不被阻塞,提高性能。文章还详细说明了异步方法的基础示例、线程调度过程、延续任务机制、同步上下文的作用以及如何使用`Task.WhenAll`和`Task.WhenAny`处理多个异步任务的并发执行。
|
2月前
|
存储 设计模式 分布式计算
Java中的多线程编程:并发与并行的深度解析####
在当今软件开发领域,多线程编程已成为提升应用性能、响应速度及资源利用率的关键手段之一。本文将深入探讨Java平台上的多线程机制,从基础概念到高级应用,全面解析并发与并行编程的核心理念、实现方式及其在实际项目中的应用策略。不同于常规摘要的简洁概述,本文旨在通过详尽的技术剖析,为读者构建一个系统化的多线程知识框架,辅以生动实例,让抽象概念具体化,复杂问题简单化。 ####
|
3月前
|
并行计算 安全 Java
Python 多线程并行执行详解
Python 多线程并行执行详解
109 3
|
5月前
|
算法 Java
JUC(1)线程和进程、并发和并行、线程的状态、lock锁、生产者和消费者问题
该博客文章综合介绍了Java并发编程的基础知识,包括线程与进程的区别、并发与并行的概念、线程的生命周期状态、`sleep`与`wait`方法的差异、`Lock`接口及其实现类与`synchronized`关键字的对比,以及生产者和消费者问题的解决方案和使用`Condition`对象替代`synchronized`关键字的方法。
JUC(1)线程和进程、并发和并行、线程的状态、lock锁、生产者和消费者问题
|
5月前
|
前端开发 JavaScript 大数据
React与Web Workers:开启前端多线程时代的钥匙——深入探索计算密集型任务的优化策略与最佳实践
【8月更文挑战第31天】随着Web应用复杂性的提升,单线程JavaScript已难以胜任高计算量任务。Web Workers通过多线程编程解决了这一问题,使耗时任务独立运行而不阻塞主线程。结合React的组件化与虚拟DOM优势,可将大数据处理等任务交由Web Workers完成,确保UI流畅。最佳实践包括定义清晰接口、加强错误处理及合理评估任务特性。这一结合不仅提升了用户体验,更为前端开发带来多线程时代的全新可能。
138 1
|
4月前
|
SQL 存储 监控
SQLServer事务复制延迟优化之并行(多线程)复制
【9月更文挑战第12天】在SQL Server中,事务复制延迟会影响数据同步性。并行复制可通过多线程处理优化这一问题,提高复制效率。主要优化方法包括:配置分发代理参数、优化网络带宽、调整系统资源、优化数据库设计及定期监控维护。合理实施这些措施可提升数据同步的及时性和可靠性。
144 0
|
5月前
|
算法 Java
JDK版本特性问题之想控制 G1 垃圾回收器的并行工作线程数量,如何解决
JDK版本特性问题之想控制 G1 垃圾回收器的并行工作线程数量,如何解决
|
6月前
|
SQL 安全
线程操纵术并行策略问题之调整并行流的并行度问题如何解决
线程操纵术并行策略问题之调整并行流的并行度问题如何解决