Welcome 微信登录

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

浅谈.NET下的多线程和并行计算(一)前言2011-08-03 博客园 lovecindywang作为一个ASP.NET开发人员,在之前的开发经历中接触多线程编程的机会并不是很多,但是随着.NET 4.0的发布临近,我越来越感受到未来的1-2年中并行计算将会有很大的应用。于是决定通过写日志的方式 来总结一下.NET 3.5下的多线程编程进而引入.NET 4.0提供的新的并行库以及新的并行编程模式和编程的 思维方式。

个人觉得在日常的编程中对于ASP.NET程序员来说使用多线程编程不是很多,其实我们无时无刻不在享 受多线程的优势。首先,WEB服务器环境就是一个多线程环境,每一个请求都是独立的线程,如果没有多 线程很难想象只能同步处理一个请求的WEB服务器有什么用,类似,我们的数据库也应该是一个多线程环 境。对于Windows应用程序的程序员来说恐怕就很难不接触多线程了,最简单的就是我们会新开线程去做 一些耗时的操作,这样就可以避免UI停止响应,在操作结束后再把操作结果应用在主线程的控件上。虽然 说这样的应用是多线程,甚至很多程序员习惯什么操作都新开一个线程去做,但是我觉得这样的多线程应 用的思维还停留在单核时代,在多核时代,我们确实可以让任务实际的并行执行而不是看上去并行执行。

首先来说说概念,进程和线程的基本的概念不用多说,自然我们也能理解一个进程至少包含一个线程 。通过在一个进程中开启多个线程,我们就可以让一个程序在同一时间看上去能做多个事情,比如可以在 接受用户响应的时候进行一些计算。在以前处理器往往只有一个核心,也就是说在同一时间,处理器只能 做一件事情。那么怎么实现之前说的多个线程同时执行呢。其实这个同时只是表面上看上去同时,本质上 多个线程依次占用处理器的若干时间片,大家轮流使用其资源,由于这个时间片非常短,所以在一个长的 时间看来似乎是几个线程同时得到了执行。

举一个生动的例子,我们经常看到有一些画家能同时在一个画布上画两个不同的图片,一个画人一个 画房子,最后一起完成这个画。但仔细看的话发现,他是两手拿了两只画笔,在这里画一笔那里画一笔, 在同一时间其实也只有一只笔在画。这个画家应该也像普通人一样是单核的,只是线程切换比较快罢了。 我经常在打电话的时候和网友进行聊天,在同一时间做两件事情,但是这样很费脑子,在打字前我要回忆 一下刚才聊天的内容,然后输入聊天的文字,然后再去回想一下刚才那哥们说了啥,在电话里面回他一句 ,这种回忆的工作就是准备线程的上下文,交给脑子去处理。虽然同一时间是做了两件事情,但是这个上 下文的准备工作也浪费了点时间,如果我在打电话网络聊天的同事在去做第三件事情比如看电影,那我估 计就不行了。所以,线程也不能开的很多,特别对于人脑来说。但是对于电脑处理器来说就不一样了,你 只要准备好数据和指令他执行就是了,至于这些事情来自几件事情它不关心,24小时一秒都不浪费在执行 指令完全没问题,当然你也可以让它闲着。

您可能会想了,既然线程切换需要时间,那么我们开两个线程执行两个任务不是还没有一个一个执行 来的快吗?其实即使对于单核的处理器都不一定,因为在实际的应用中我们的任务往往不可能从头计算到 尾一直占用处理器资源,在很多时候我们要等待IO响应或用户的响应,如果只是一个线程做事情的话处理 器太闲了。对于现在多核的处理器来说,在同一时刻理论上可以在每一个处理器上都并行执行指令,我们 就更需要利用多线程来提高运算速度了。当然也不是说一个任务要执行10秒,我们在双核的机器上并行执 行这个任务只需要5秒了,那是因为很多时候这个任务很难划分成两个分支来并行执行,如果每个指令都 要依靠上个指令的执行结果,那么这样的操作很难在多个处理器上并行执行。但是,我们可以这样想,至 少如果有两个这样任务的话,我们就可以完全利用多个处理器的优势来并行执行了。

但是也不是多可以随便的开线程,每一个线程默认情况下都会占用1M的栈空间(对于普通应用程序来 说),在32位Windows平台下可以给一个用户进程使用的程序最大在2G,那么也就是说在程序中使用的线 程不能超过2000个,在实际测试中可以发现一般来说开1930左右个线程就会收到内存不足的异常,其实这 个数量是绝对够用的,即使复杂的Outlook2007程序一般也只用了50个不到的线程(可以在任务管理器中 观察到)。

在不得已的情况下很多人都不太会去使用多线程也是有原因的,一是因为多线程编程复杂,我们也习 惯了一行一行代码执行的编程模式,对于一个好的多线程程序来说,要尽量分割任务让它在多个线程中使 用以利用到多个处理器核。还有就是多个线程使用相同资源的话还要考虑资源的锁定以免产生数据的不一 致。锁定/ 事务/并发的概念在数据库中也是非常常见的。二是因为调试困难,特别是一个线程的执行依 赖其它线程的执行。三是因为多线程的程序随着环境的变化(处理器 /操作系统)可能执行的性能还不一 定相同,如果只针对某个环境进行编程可能还不能充分利用多处理器的优势。比如我们对一个任务划分成 2个线程并行执行,那么对于四核的处理器来说,划分成4个线程并行执行会不会更合理呢,说实话我也举 的这事挺难说的?还有,我们的编程基于.NET框架,而其本质还是使用的是操作系统的线程,操作系统中 本来就有很多进程运行着,处理器是大家的处理器,不是专供我们程序使用的,在这么一个鱼龙混杂的环 境,我们的程序究竟是不是会表现的如我们预期那样,也很难说。

多线程好,多线程难,本系列文章也只能在一个比较浅显的层次来谈谈如何在.NET框架中进行多线程 编程,以及一些常见应用(比如Windows应用)中多线程的典型应用。本系列文章预计会有30篇这样的规 模,希望对大家有帮助。