Chapter 19. 线程
C#允许你通过多线程来并行地执行代码。
一个线程近似于你的应用程序运行于其中的操作系统进程。只是进程并行地运行于一个计算机上,而线程并行地运行于一个单一的进程内。进程之间是完全孤立的;线程则是有限度地孤立。特别地,线程与运行在相同应用程序域中的其它线程共享(堆)内存。、这个,部分地,是线程为什么有用的原因:一个线程可以在后台抓取数据,同时另外一个线程可以显示数据,当数据到达时。
这一章描述用于创建、配置、和与其它线程通信的语言和框架特征,以及如何通过锁定(locking)与信令(signaling)指挥它们的行为。本章也覆盖了辅助线程的预定义类型:BackgroundWorker、ReaderWriterLock、和Timer类。
19.1 线程的使用和误用
多线程的一个普遍的应用是当执行一个耗费时间的任务时保持用户界面的响应性。如果耗费时间的任务工作在一个并行的“工作(worker)”线程上,主线程就可以自由地连续处理键盘和鼠标事件。
不管是否一个用户界面被包括在内,当等待从另一台计算机或者一个硬件来的响应时,多线程可以是有用的。如果一个工作线程执行任务,鼓动者(译者注:即创建工作线程的线程)就可以立即利用否则就是没有负荷的计算机(译者注:如果没有那个工作线程,计算机就是没有负荷的)去自由地做其它事情,
另一个多线程的用途是书写执行密集计算的方法。如果工作负荷被在两个或者更多的线程之间共享,这些方法能够在多处理器或者多核计算机上执行地更快。异步委托就特别适合于这种情况。(你可以通过Environment.ProcessorCount属性来测试处理器的数量。)
.NET框架的一些特征隐含地创建线程。如果你使用ASP.NET、WCF、Web Services、或者Remoting,进入的客户请求能够并发地到达服务器。你可能意识不到多线程正在进行,除非你使用静态字段缓存数据而不恰当地锁定,(译者注:导致)与线程安全相冲突。
线程也是带着附加条件来的。最大的(译者注:一个附加条件)是多线程可以增加复杂性。拥有大量线程本身并不产生复杂性;是线程之间的交互(典型地借助于共享数据)产生复杂性。这意味着不管交互是否是有意的,都能够导致长的开发周期和对间歇性的以及不可再生的bug的持续的感受。由于这个原因,保持交互最小化是值得的,并且只要有可能就坚持简单和被证明过的设计。这一章花费大量篇幅对付这些复杂性;去掉了交互,这里就几乎无话可说了。
在分配和切换线程的过程中也办伴随着一个资源和CPU的消耗。多线程并不总是加速你的应用程序—如果过度和不当使用,它甚至可以降低它(译者注:指应用程序的运行速度)。例如,当涉及到繁重的磁盘I/O时,使用一对工作线程顺序地运行任务而不是使用10个线程同时执行可以更快地(译者注:完成任务)。(在后面的“19.9节”,我们描述如何实现一个生产者/消费者队列,它提供的就是这种功能。)