托管线程池 |
ThreadPool类为应用程序提供一个由系统管理的辅助线程池,从而使您可以集中精力于应用程序任务而不是线程管理。如果您具有需要后台处理的短期任务,则托管线程池是可以利用多个线程的便捷方式。
说明 |
---|
从 .NET Framework 2.0 Service Pack 1 开始,线程池的吞吐量在三个关键方面得到了显著提高:让任务排队、调度线程池线程和调度 I/O 完成线程,在 .NET Framework 的早期版本中这三个方面被视为瓶颈。若要使用此功能,您的应用程序应面向 .NET Framework 3.5 版。有关更多信息,请参见.NET Framework Architecture。 |
对于与用户界面交互的后台任务,.NET Framework 2.0 版还提供了BackgroundWorker类,该类可以使用用户界面线程中引发的事件进行通信。
.NET Framework 使用线程池线程实现多种用途,包括异步 I/O 完成、Timer 回调、注册的等待操作、使用委托的异步方法调用以及System.Net套接字连接。
在以下几种情况下,适合于创建并管理自己的线程而不是使用线程池线程:
-
需要前台线程。
-
需要使线程具有特定的优先级。
-
您的任务会导致线程长时间被阻塞。由于线程池具有最大线程数限制,因此大量阻塞的线程池线程可能会阻止任务启动。
-
需要将线程放入单线程单元。所有ThreadPool线程均处于多线程单元中。
-
您需要具有与线程关联的稳定标识,或使某一线程专用于某一任务。
线程池线程是后台线程。请参见前台和后台线程。每个线程都使用默认堆栈大小,以默认的优先级运行,并处于多线程单元中。
每个进程只有一个线程池对象。
线程池线程中的异常
线程池线程中未经处理的异常将终止进程。以下为此规则的三种例外情况:
-
由于调用了Abort,线程池线程中将引发ThreadAbortException。
-
由于正在卸载应用程序域,线程池线程中将引发AppDomainUnloadedException。
-
公共语言运行时或宿主进程将终止线程。
有关更多信息,请参见托管线程中的异常。
最大线程池线程数
可排队到线程池的操作数仅受可用内存的限制;但是,线程池限制进程中可以同时处于活动状态的线程数。默认情况下,限制每个 cpu 只能使用 250 个辅助线程和 1,000 个 I/O 完成线程。
通过使用GetMaxThreads和SetMaxThreads方法可以控制最大线程数。
最小空闲线程数
即使是在所有线程都处于空闲状态时,线程池也会维持最小的可用线程数,以便队列任务可以立即启动。将终止超过此最小数目的空闲线程,以节省系统资源。默认情况下,每个处理器维持一个空闲线程。
在启动新的空闲线程之前,线程池具有一个内置延迟(在 .NET Framework 2.0 版中为半秒钟)。应用程序在短期内定期启动许多任务时,空闲线程数的微小增加会导致吞吐量显著增加。将空闲线程数设置得过高会浪费系统资源。
使用GetMinThreads和SetMinThreads方法可以控制线程池所维持的空闲线程数。
线程池还提供了ThreadPool.UnsafeQueueUserWorkItem和ThreadPool.UnsafeRegisterWaitForSingleObject方法。仅在确定调用方的堆栈与执行排队任务的过程中执行的任何安全检查无关时使用这些方法。QueueUserWorkItem和RegisterWaitForSingleObject都捕获调用方的堆栈,在线程开始执行任务时将此堆栈合并到线程池线程的堆栈中。如果需要进行安全检查,则必须检查整个堆栈。尽管此检查提供了安全,但它还具有一定的性能开销。
使用线程池的方式是,从托管代码调用ThreadPool.QueueUserWorkItem(或从非托管代码调用CorQueueUserWorkItem)并传递表示执行任务的方法的WaitCallback委托。也可以通过使用ThreadPool.RegisterWaitForSingleObject方法并传递WaitHandle(在向其发出信号或超时时,它将引发对WaitOrTimerCallback委托表示的方法的调用)来将与等待操作相关的工作项排入队列。在这两种情况下,线程池都使用一个后台线程来调用回调方法。
以下三个代码示例演示RegisterWaitForSingleObject方法。
第一个示例使用QueueUserWorkItem方法将一个由ThreadProc方法表示的非常简单的任务排入队列。
为 QueueUserWorkItem 提供任务数据
RegisterWaitForSingleObject
下面的示例演示几种线程处理功能。
-
使用RegisterWaitForSingleObject方法将任务排队,以由ThreadPool线程执行。
-
使用AutoResetEvent发出信号,通知执行任务。请参见EventWaitHandle、AutoResetEvent、CountdownEvent 和 ManualResetEvent。
-
使用WaitOrTimerCallback委托处理超时和信号。
-
使用RegisteredWaitHandle取消排入队列的任务。