C#3.0核心技术-第19章线程-全新翻译注释-19.2(4)

来源:互联网 发布:数据库测试用例怎么写 编辑:程序博客网 时间:2024/04/30 10:58

19.2.3 线程池

无论任何时候你开始一个线程,几百微秒将会被花费在组织诸如一个全新的私有局部变量栈(译者注:的事情上)。每个线程也大约消耗1MB左右的内存。线程池通过共享和回收线程来去掉这些开销,允许多线程被应用到更小粒度的水平而没有性能损失。

进入线程池最容易的方式是通过调用ThreadPool.QueueUserWorkItem代替实例化和开始一个Thread对象。这里是例子:

clip_image001

我们的目标方法,Go,必须接受一个单一的object参数(以满足WaitCallback委托(译者注:的定义))。这提供一个方便的传送数据到方法的方式,就像ParameterizedThreadStart方法一样。

线程池也对同时运行的工作线程的总数保持了一个限制。太多线程造成的管理负担会扼杀操作系统。你能够通过调用ThreadPool.SetMaxThreads设置上限;缺省值是50(这个值会根据硬件和操作系统的不同而有所不同)。一旦超过(译者注:这个值),工作开始排队并仅当另外的(译者注:线程)运行完毕才开始运行。

线程池使任意并发的应用程序成为可能,例如一个Web服务器。如果你在服务器上为每一个客户请求开始一个新线程,一个很厉害的迸发式的并发客户端活动能够阻塞服务器。线程池通过限制活动线程的数量来解决这个问题(译者注:即如果客户端的并发请求的数目超过线程池中线程的上限,则超过的请求会因为排队而被阻塞)。(异步方法模式通过对线程池线程的高效使用向前更进了一步;见第20章)

你在每个应用程序中仅能获得一个线程池。你能够通过Thread.CurrentThread. IsThread-PoolThread属性查询你是否正运行在一个线程池线程中。

原文注:

下列自动使用线程池:

异步代理

BackgroundWorker帮助类

System.Timer.Timer和System.Threading.Timer

WCF,Remoting,ASP.NET,和Web服务应用服务器

19.2.3.1 优化线程池

池管理器仅当需要时创建线程;这确保了一个“Hello,world”程序不会分配50个线程和消耗50MB内存(译者注:这里的意思是,因为每个应用程序可以有一个线程池,且缺省上限是50个线程,而一个仅仅打印“Hello,world”的程序是不会被在开始运行时就立即分配一个有50个线程的线程池,原因就在于池管理器按需创建线程)。但是假设一个程序像下面一样迅速地将50个任务放入池的队列中:

clip_image002

池管理器不再生成50个线程。实际上,从一开始,它就会停在处理器的数目上或者CPU的核数上;在一个双核计算机上,池管理器将创建恰好两个线程并将剩余的48个工作排队在这两个线程上。匹配线程数到内核数允许一个程序保持一个小的计算机空间占用而不伤害性能(译者注:因为通常空间少和性能高是两个矛盾的事物)—只要线程被有效的使用(在这种情况下它们是这样的)。但是现在假定我们在计算hash之前插入了一个Thread.Sleep语句,使CPU空闲一段时间(或者运行一个耗费时间的数据库查询(译者注:以达到同Thread.Sleep语句同样的效果))。池管理器的线程经济性(译者注:类似于燃油经济性)策略失败了(译者注:指一个工作即使在睡眠时也占用了线程池中的一个线程,使其它工作无法得到线程而执行);它现在最好创建50个线程,使得所有工作都能够同时睡眠(或等待数据库服务器)。

幸运的是,池管理器有一个备用方案。如果它的队列保持稳定半秒以上(译者注:指半秒时间内还没有队列中的工作被处理),它通过创建更多的线程来响应—每半秒一个—直到线程池的容量。一旦被创建,线程将在线程池中终其一生,所以它将总是立即可用于服务新的请求。

半秒的延迟是一个双刃剑。一方面,它意味着一次性迸发的短暂性活动(例如在我们的例子中,没有睡眠(译者注:指本节第一个例子))不会使得一个程序突然消耗一个额外不需要的50MB内存。另一方面,它可以在一个池线程阻塞的时候造成不必要的延迟,诸如当查询一个数据库或者调用WebClient.DownloadFile。由于这个原因,你可以告诉池管理器在分配前x个线程时不要延迟,像下面一样:

clip_image003

(译者注:

public static bool SetMinThreads(

int workerThreads,

int completionPortThreads

workerThreads

Type: System.Int32
The new minimum number of idle worker threads to be maintained by the thread pool.

completionPortThreads

Type: System.Int32
The new minimum number of idle asynchronous I/O threads to be maintained by the thread pool.

Remarks

--------------------------------------------------------------------------------

Idle threads are maintained by the thread pool in order to reduce the time required to satisfy requests for thread pool threads. Separate minimums are maintained for worker threads and asynchronous I/O threads. Idle threads in excess of the minimums are terminated, to save system resources. Maintenance of the idle threads is a background task.)

这在使用线程池的客户端程序中是有意义的;如果你使用一个诸如WCF或者ASP.NET的技术写一个应用服务器,基础架构会自动做这些。

原创粉丝点击