线程(多通道模式)
进程我们都知道计算机的核心是CPU,承担所有的计算任务; *** 作系统是计算机的管理者,负责任务调度、资源分配和管理,统领整个计算机硬件;应用程序是运行在 *** 作系统上的具有一定功能的程序。
进程是具有一定独立功能的程序在数据集上的动态执行过程,是 *** 作系统进行资源分配和调度的独立单元,是应用程序运行的载体。过程是一个抽象的概念,从来没有统一的标准定义。
通常,一个过程由三部分组成:程序、数据收集和过程控制块。
后来随着计算机的发展,对CPU的要求越来越高,进程间的切换代价昂贵,已经不能满足越来越复杂的程序的要求。所以我发明了线。
它是线程程序执行中的单个顺序控制流,是程序执行流的最小单位,也是处理器调度和分派的基本单位。一个进程可以有一个或多个线程,每个线程共享程序的内存空(也就是自己进程的内存空)。一个标准线程由线程ID、当前指令指针(PC)、寄存器和堆栈组成。进程由内存空(代码、数据、进程空、打开的文件)和一个或多个线程组成。
(有些读者看到这里可能会很困惑,觉得这和Java的memory 空模型不一样,但是如果你看过《Java虚拟机深度理解》这本书,你就会恍然大悟。)
如上图,在任务管理器的进程列中,一个字典和一个云笔记是进程,进程下有多个线程执行不同的任务。
任务调度什么是线程?要理解这个概念,我们需要了解 *** 作系统的一些相关概念。大多数 *** 作系统(如Windows、Linux)采用时间片轮换的抢占式调度方式。
在一个进程中,当一个线程的任务执行了几个毫秒,就会被 *** 作系统的内核(负责管理每个任务)调度。处理器将被硬件计数器中断,线程将被迫暂停,其寄存器将被放入内存。通过检查线程列表,它会决定下一步执行哪个线程,并从内存中回收该线程的寄存器,最后恢复该线程的执行,从而执行下一个任务。
在上述过程中,一个任务被执行的短暂时间称为时间片,任务正在被执行的状态称为运行状态,被挂起的线程任务状态称为就绪状态,即等待属于它的下一个时间片。
这种方式保证了每个线程轮流执行。因为CPU的执行效率非常高,时间片非常短,在任务之间快速切换,给人多任务“同时”的感觉,这就是我们所说的并发(不要以为并发有多高级,它的实现很复杂,但它的概念很简单,就是一句话:多个任务同时执行)。多任务 *** 作流程示意图如下:
*** 作系统中的任务调度
进程与线程的区别前面讲了进程和线程,大家可能还是会觉得很困惑,觉得很像。事实上,进程与线程密不可分。让我们一起来看看它们:
与流程的资源共享关系
单线程和多线程的关系
总之,线程和进程都是抽象概念。线程是比进程更小的抽象,线程和进程都可以用来实现并发。
在早期的 *** 作系统中,没有线程的概念。进程是能够拥有资源并独立运行的最小单位,也是程序执行的最小单位。相当于一个进程中只有一个线程,进程本身就是一个线程。因此,线程有时被称为轻量级进程(LWP)。
早期的 *** 作系统只有进程,没有线程。
后来随着计算机的发展,多任务间的上下文切换效率越来越高,于是抽象出一个更小的概念——线程。通常,一个进程会有多个(或一个)线程。
线程的出现允许一个进程拥有多个线程。
多线程与多核上述时间片轮换的调度方式是指一个任务经过一小段时间后强制暂停执行下一个任务,每个任务依次执行。很多 *** 作系统书都说“同一时间只执行一个任务”。那么可能有人要问双核处理器了?两个核心不是同时运行吗?
其实“同时只执行一个任务”这句话是不准确的,至少是不完整的。在多核处理器的情况下,线程如何执行?这需要了解内核线程。
多核(core)处理器是指在一个处理器上集成多个计算核心来提高计算能力,即有多个处理核心进行真正的并行计算,每个处理核心对应一个内核线程。
内核线程(KLT)是由 *** 作系统内核直接支持的线程。这种线程由内核切换,内核通过 *** 作调度器调度线程,负责将线程的任务映射到各个处理器。一般一个处理核心对应一个内核线程,比如单核处理器对应一个内核线程,双核处理器对应两个内核线程,四核处理器对应四个内核线程。
现在的电脑一般都是双核四线程,四核八线程。超线程技术是将一个物理处理核心模拟成两个逻辑处理核心,对应两个内核线程,所以 *** 作系统中看到的CPU数量是实际物理CPU的两倍。例如,如果您的计算机是双核四线程,请打开任务管理器\性能查看四个CPU的监视器,打开四核八线程查看八个CPU的监视器。
在Windows8中查看四核线程的结果
超线程技术是利用特殊的硬件指令将一个物理芯片模拟成两个逻辑处理核心,使单个处理器可以使用线程级并行计算,从而兼容多线程 *** 作系统和软件,减少CPU的空闲时间,提高CPU的运行效率。这种超线程技术(如双核四线程)是由处理器的硬件决定的,也需要 *** 作系统的支持才能在电脑中显示。
程序一般不直接使用内核线程,而是使用内核线程的一个高级接口——轻量级进程(LWP)。轻量级进程就是我们通常所说的线程,也叫用户线程。由于每个轻量级进程都是由一个内核线程支持的,所以只有首先支持内核线程,才能有轻量级进程。用户与内核线程的对应关系有三种模型:一对一模型、多对一模型和多对多模型。这里以四个内核线程和三个用户线程为例来说明这三种模型。
一对一模型对于一对一模型,一个用户线程唯一对应一个内核线程(反之不一定成立,内核线程也不一定有对应的用户线程)。这样,如果CPU不采用超线程技术(如四核四线程计算机),一个用户线程唯一映射到一个物理CPU的内核线程,线程间的并发就是真并发。一对一的模式使得用户线程拥有和内核线程一样的优势。当一个线程因为某种原因被阻塞时,其他线程的执行不会受到影响。在这里,一对一模型也可以使多线程程序在多处理器系统上执行得更好。
但是一对一模式也有两个缺点:
多对一模型将多个用户线程映射到一个内核线程,线程之间的切换由用户态代码完成,所以系统内核感受不到线程的实现。用户线程的建立、同步和销毁都在用户态完成,不需要内核的干预。所以相对于一对一模型,多对一模型的线程上下文切换速度要快很多;此外,多对一模型对用户线程的数量几乎没有限制。
但是多对一模型也有两个缺点:
多对多模型结合了一对一模型和多对一模型的优点,将多个用户线程映射到多个内核线程。线程库负责在可用的可调度实体上调度用户线程,这使得线程的上下文切换非常快,因为它避免了系统调用。然而,它增加了复杂性和优先级反转的可能性,以及在用户模式调度程序和内核调度程序之间没有广泛(且昂贵)协调的情况下的次优调度。
多对多模型的优点是:
多对多模型主要用于流行的 *** 作系统。
查看进程与线程应用程序可以是多线程或多进程的。怎么查?在Windows下,我们只能通过打开任务管理器来查看一个应用的进程和线程的数量。按“Ctrl+Alt+Del”或右键单击快捷工具栏打开任务管理器。
查看进程和线程的数量:
查看线程和进程的数量
在“Processes”选项卡下,我们可以看到应用程序中包含的线程数量。如果一个应用程序有多个进程,我们可以看到每个进程。比如谷歌的Chrome浏览器就有多个进程。同时,如果打开一个应用程序的多个实例,就会有多个进程。如上图所示,如果我打开两个cmd窗口,就会有两个cmd进程。如果看不到线程数,可以再次点击“查看\选择栏目”菜单添加栏目收听。
检查CPU和内存使用情况:
在performance选项卡中,我们可以查看CPU和内存使用情况,还可以根据CPU使用情况记录的监视器数量查看逻辑处理核心的数量。比如我的双核四线程电脑,有四台显示器。
检查CPU和内存使用情况。
线程的生命周期
当线程数小于处理器数时,线程并发为真,不同的线程运行在不同的处理器上。但是,当线程数量大于处理器数量时,线程的并发性就会受到阻碍。这时候就不是真正的并发了,因为至少一个处理器会运行多个线程。
并发是单个处理器运行多个线程时的模拟状态。 *** 作系统使用时间片轮换来依次执行每个线程。现在几乎所有的现代 *** 作系统都采用了时间片轮换的抢占式调度方式,比如我们熟悉的Unix、Linux、Windows、macOS等流行的 *** 作系统。
我们知道线程是程序执行的最小单位,也是任务执行的最小单位。在早期只有进程的 *** 作系统中,进程有五种状态:创建、就绪、运行、阻塞(等待)和退出。早期进程相当于只有单线程的当前进程,所以当前多线程有五种状态,当前多线程的生命周期和早期进程类似。
早期流程的生命周期
运行过程中有三种状态:就绪、运行、阻塞、创建和退出状态描述了创建和退出一个进程的过程。
因为它们是自主开发的异步任务,所以很多人更愿意称之为纤程,或者GreenThread。正如一个进程可以有多个线程一样,一个线程也可以有多个协程。
协程的目的在传统的J2EE系统中,每个请求占用一个线程来完成完整的业务逻辑(包括事务)。所以系统的吞吐能力取决于每个线程的运行时间。如果遇到一个耗时的I/O行为,整个系统的吞吐量会立刻下降,因为这个时候线程总是被阻塞的。如果有很多线程,就会有很多线程闲置(等待线程执行完),导致资源应用不完整。
最常见的例子是JDBC(同步阻塞),这就是为什么很多人说数据库是瓶颈。这里的耗时实际上是让CPU一直等待I/O返回。说白了就是线程处于空 turn状态,根本不用CPU做运算。此外,过多的线程也会带来更多的ContextSwitch开销。
对于以上问题,现阶段业界比较流行的解决方案之一是单线程加异步回调。其代表是node.js和Vert.x,Java的新秀。
协同学的目的是通过放弃当前协同学调度并在有长时间I/O *** 作时执行下一个任务来消除ContextSwitch的开销。
协程的特点因为协调过程的暂停完全由程序控制,它发生在用户状态;但是,线程的阻塞状态是由 *** 作系统的内核切换的,这发生在内核状态。
所以协程的开销远小于线程,所以ContextSwitch上没有开销。
协程和线程的比较比较线程协作占用资源的初始单位是1MB,固定的初始通常是2KB,可以根据需要增加。调度属于OS的内核,用户完成切换开销,涉及模式切换(从用户模式切换到内核模式),16个寄存器,PC,SP # 8230只有三个寄存器值被修改,比如寄存器刷新 # 8211;PC/SP/DX。性能问题资源占用过高,频繁的创建和销毁会带来严重的性能问题。资源占用小,不会带来严重的性能问题。数据同步需要锁等机制来确保数据的连续性和可见性。没有多线程锁机制,因为只有一个线程,不存在同时写变量的冲突。在协同过程中控制共享资源时只需要判断状态,所以执行效率远高于多线程。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)