-
C#线程 入门- 线程如何工作
线程如何工作
多线程由线程调度程序在内部进行管理,这是CLR通常委托给操作系统的功能。线程调度程序确保为所有活动线程分配适当的执行时间,并且正在等待或阻塞的线程(例如,排他锁或用户输入)不会浪费CPU时间。
在单处理器计算机上,线程调度程序执行时间切片-在每个活动线程之间快速切换执行。在Windows下,时间片通常在数十毫秒的区域中-远大于在一个线程与另一个线程之间实际切换上下文时的CPU开销(通常在几微秒的区域)。
在多处理器计算机上,多线程是通过时间片和真正的并发实现的,其中不同的线程在不同的CPU上同时运行代码。几乎可以肯定,由于操作系统需要服务自己的线程以及其他应用程序的线程,因此还会有一些时间片。
当线程的执行由于外部因素(例如时间分段)而中断时,可以说该线程被抢占。在大多数情况下,线程无法控制其抢占的时间和地点。
线程与进程
线程类似于您的应用程序在其中运行的操作系统进程。正如进程在计算机上并行运行一样,线程在单个进程中并行运行。流程彼此完全隔离;线程的隔离度有限。特别是,线程与在同一应用程序中运行的其他线程共享(堆)内存。这部分是为什么线程有用的原因:例如,一个线程可以在后台获取数据,而另一个线程可以在数据到达时显示数据
线程的使用和滥用
多线程有很多用途。这是最常见的:
维护响应式用户界面
通过在并行的“工作者”线程上运行耗时的任务,主UI线程可以自由继续处理键盘和鼠标事件。
有效利用原本被阻塞的CPU
当线程正在等待另一台计算机或硬件的响应时,多线程很有用。当一个线程在执行任务时被阻塞时,其他线程可以利用原本没有负担的计算机。
并行编程
如果以“分而治之”策略在多个线程之间共享工作负载,则执行密集计算的代码可以在多核或多处理器计算机上更快地执行(请参阅第5部分)。
投机执行
在多核计算机上,有时可以通过预测可能需要完成的事情然后提前进行来提高性能。 LINQPad使用此技术来加快新查询的创建。一种变化是并行运行许多不同的算法,这些算法都可以解决同一任务。不论哪一个先获得“胜利”,当您不知道哪种算法执行最快时,这才有效。
允许同时处理请求
在服务器上,客户端请求可以同时到达,因此需要并行处理(如果使用ASP.NET,WCF,Web服务或远程处理,.NET Framework会为此自动创建线程)。这在客户端上也很有用(例如,处理对等网络-甚至来自用户的多个请求)。
使用ASP.NET和WCF之类的技术,您可能甚至不知道多线程正在发生-除非您在没有适当锁定的情况下访问共享数据(也许通过静态字段),否则会破坏线程安全性。
线程还附带有字符串。最大的问题是多线程会增加复杂性。有很多线程本身并不会带来很多复杂性。确实是线程之间的交互(通常是通过共享数据)。无论交互是否是有意的,这都适用,并且可能导致较长的开发周期以及对间歇性和不可复制错误的持续敏感性。因此,必须尽量减少交互,并尽可能地坚持简单且经过验证的设计。本文主要侧重于处理这些复杂性。删除互动,无需多说!
好的策略是将多线程逻辑封装到可重用的类中,这些类可以独立检查和测试。框架本身提供了许多更高级别的线程结构,我们将在后面介绍。
线程化还会在调度和切换线程时(如果活动线程多于CPU内核)会导致资源和CPU成本的增加,并且还会产生创建/拆除的成本。多线程并不总是可以加快您的应用程序的速度-如果使用过多或使用不当,它甚至可能减慢其速度。例如,当涉及大量磁盘I / O时,让几个工作线程按顺序运行任务比一次执行10个线程快得多。 (在“使用等待和脉冲发送信号”中,我们描述了如何实现仅提供此功能的生产者/消费者队列。)