存器,这也就是线程运行的主要战场。操作系统中那么多线程(一般都有上千个线程,大
部分都处于休眠状态),对于单核 CPU,一次只能有一个线程被调度执行,那么多线程怎
么分配的呢?Windows 系统采用时间轮询机制,CPU 计算资源以时间片(大约 30ms)的形式
分配给执行线程。
计算机资源(CPU 核心和 CPU 寄存器)一次只能调度一个线程,具体的调度流程:
把 CPU 寄存器内的数据保存到当前线程内部(线程上下文等地方),给下一个线程腾
地方;
线程调度:在线程集合里取出一个需要执行的线程;
加载新线程的上下文数据到 CPU 寄存器;
新线程执行,享受她自己的 CPU 时间片(大约 30ms),完了之后继续回到第一步,
继续轮回;
上面线程调度的过程,就是一次线程切换,一次切换就涉及到线程上下文等数据的搬
入搬出,性能开销是很大的。因此线程不可滥用,线程的创建和消费也是很昂贵的,这也
是为什么建议尽量使用线程池的一个主要原因。
对于 Thread 的使用太简单了,这里就不重复了,总结一下线程的主要几点性能影响:
线程的创建、销毁都是很昂贵的;
线程上下文切换有极大的性能开销,当然假如需要调度的新线程与当前是同一线程的
话,就不需要线程上下文切换了,效率要快很多;
这一点需要注意,GC 执行回收时,首先要(安全的)挂起所有线程,遍历所有线程栈
(根),GC 回收后更新所有线程的根地址,再恢复线程调用,线程越多,GC 要干的活就
越多;
当然现在硬件的发展,CPU 的核心越来越多,多线程技术可以极大提高应用程序的效
率。但这也必须在合理利用多线程技术的前提下,了线程的基本原理,然后根据实际需求,
还要注意相关资源环境,如磁盘 IO、网络等情况综合考虑。
多线程
单线程的使用这里就略过了,那太 easy 了。上面总结了线程的诸多不足,因此微软提
供了可供多线程编程的各种技术,如线程池、任务、并行等等。
线程池 ThreadPool
线程池的使用是非常简单的,如下面的代码,把需要执行的代码提交到线程池,线程
池内部会安排一个空闲的线程来执行你的代码,完全不用管理内部是如何进行线程调度的。
ThreadPool.QueueUserWorkItem(t => Console.WriteLine("Hello thread pool"));
每个 CLR 都有一个线程池,线程池在 CLR 内可以多个 AppDomain 共享,线程池是 CLR 内部
管理的一个线程集合,初始是没有线程的,在需要的时候才会创建。线程池的主要结构图
如下图所示,基本流程如下:
线程池内部维护一个请求列队,用于缓存用户请求需要执行的代码任务,就是
ThreadPool.QueueUserWorkItem 提交的请求;
有新任务后,线程池使用空闲线程或新线程来执行队列请求;
任务执行完后线程不会销毁,留着重复使用;
线程池自己负责维护线程的创建和销毁,当线程池中有大量闲置的线程时,线程池会
自动结束一部分多余的线程来释放资源;