- 轻量级进程 和 内核线程 一对一相互映射实现的 1:1 线程模型
- 用户线程 和 内核线程 实现的 N:1 线程模型
- 用户线程 和 轻量级进程 混合实现的 N:M 线程模型
1:1线程模型
- 内核线程( Kernel-Level Thread )是由操作系统 内核 支持的线程,内核通过 调度器 对线程进行调度,负责完成线程的 切换
- 在Linux中,往往通过 fork 函数创建一个 子进程 来代表一个 内核中的线程
- 一个进程调用fork函数后,系统会先给新的子进程 分配资源 ,然后 复制 主进程,只有少数值与主进程不一样
- 采用fork的方式,会产生大量的 冗余 数据,占用 大量内存空间 ,也会消耗 大量CPU时间 来初始化内存空间和复制数据
- 如果是一模一样的数据,可以 共享 主进程的数据,于是轻量级进程( Light Weight Process,LWP )出现了
- LWP使用 clone 系统调用创建线程
- clone函数将 部分 父进程的资源的数据结构进行复制,复制内容 可选 ,且没有被复制的资源可以通过 指针 共享给子进程
- LWP 运行单元更小 , 运行速度更快 ,LWP和内核线程 一一映射 ,每个LWP都是由一个内核线程支持
N:1线程模型
- 1:1线程模型的缺陷
- 在线程创建、切换上都存在 用户态和内核态的切换
- 系统资源有限, 无法支持创建大量LWP
- 该线程模型在 用户空间 完成了线程的创建、同步、销毁和调度,并不需要内核的帮助, 不会产生用户态和内核态的空间切换
N:M线程模型
- N:1线程模型的缺陷
- 操作系统无法感知用户态的线程 ,容易造成某个线程进行 系统调用 内核线程时被阻塞,从而导致 整个进程被阻塞
- N:M线程模型是一种 混合 线程管理模型
- 支持 用户态线程 通过 LWP 与 内核线程 连接, 用户态的线程数量 和 内核态的LWP数量 是N:M的映射关系
Java线程 / Go协程
- Java线程
- Thead#start通过调用native方法 start0 实现
- 在Linux下,JVM Thread是基于 pthread_create 实现的,而pthread_create实际上调用了 clone 系统调用来创建线程
- 所以,Java在Linux下采用的是 1:1线程模型 (用户线程与轻量级线程一一映射),线程通过 内核调度 ,涉及 上下文切换
- Go协程
- Go语言使用了 N:M线程模型 实现了 自己的调度器 ,在 N个内核线程上多路复用M个协程
- 协程的上下文切换在 用户态 由 协程调度器 完成, 不需要陷入到内核 ,相比Java线程, 代价很小
协程的实现原理
- 协程可以看作 一个类函数 或者 一块函数中的代码 ,可以在主线程里面轻松创建多个协程
- 程序调用协程和调用函数是不一样的,协程可以通过 暂停 或者 阻塞 的方式将协程的执行挂起,而其他协程可以继续执行
- 协程的挂起只是在程序中( 用户态 )的挂起,同时将代码 执行权 转让给其他协程使用
- 待获取执行权的协程执行完之后,将从挂起点唤醒挂起的协程
- 协程的 挂起 和 唤醒 是通过一个 调度器 完成的
图例解释
- 假设程序中默认创建两个线程为协程使用,在主线程中创建协程ABCD…,分别存储在 就绪队列 中
- 调度器首先会分配工作线程A执行协程A,工作线程B执行协程B,其他创建的协程将会在 等待队列 中进行排队等待
- 当协程A调用 暂停方法 或 被阻塞 时,协程A会进入到 挂起队列 ,调度器会调用 等待队列 中的其他协程 抢占 线程A执行
- 当协程A 被唤醒 时,它需要重新进入到 就绪队列 中,通过调度器 抢占 线程
- 如果抢占成功,就继续执行协程A;如果抢占失败,就继续等待抢占线程
线程 / 协程
- 相比于线程,协程少了由于同步资源 竞争 带来的 CPU上下文切换
- 应用场景: IO阻塞型场景
- 比较适合 IO密集型 的应用,特别在 网络请求 中,有较多的时间在等待服务端响应
- 协程可以 保证线程不会阻塞在等待网络响应 (可以在协程层面阻塞)中,充分利用了多核多线程的能力
- 对于CPU密集型的应用,由于多数情况下CPU都比较繁忙,协程的优势就不会特别明显
- 线程是通过 共享内存 的方式来实现数据共享,而协程是使用了 通信 (MailBox)的方式来实现数据共享
- 这主要为了避免内存共享数据而带来的 线程安全 问题
小结
- 协程可以认为是 运行在线程上的代码块 ,协程提供的 挂起 操作会使 协程暂停执行 ,而 不会导致线程阻塞
- 协程是一种 轻量级资源 ,即使创建上千个协程,对系统来说也不会是很大的负担,而线程则不然
原文
http://zhongmingmao.me/2019/09/02/java-performance-coroutine/