1.操作系统主流的线程模型
1:1 线程模型
-
N:1 线程模型
-
M:N线程模型
M个用户线程对应N个内核线程
-
2.不同线程模型如何编写高性能TCP服务
适合1:1 线程模型的编程模型
1:1的线程模型, 如果使用BIO的那套网络服务编写方式, 会创造大量线程
而我们现在是1:1的线程模型, 对机器的负载会变得越来越高, 大量的CPU时间片会用在线程切换上 所以1:1线程模型, 想要有高性能的TCP服务就要用事件驱动的编程模型
N:1
适合 M:N 线程模型的编程模型
这里有个典型代表就是golang, golang的goroutine是一个轻量级线程, 也就是协程
goroutine之间切换, 内核并不知道, 非常轻量级, 单核CPU可以很轻松的创造几十万的协程
这种线程模型就没有必要搞那些花里胡哨的, 直接大力出奇迹, 就用BIO的编程模型就行3.Java的线程模型
Java的线程与操作系统的线程是 一一对应的, 也就是经典的 1:1 模型
- 在Linux中实际上process和thread是一回事, 区别就在于是否共享地址空间
- 这也就是说在Java中创建线程代价是很大的
- 基于上面的原因, 如果想在Java中开发高性能的TCP服务, 就只有一条路子了, 就是使用事件驱动的编程模型
JavaNIO是事件驱动模型, 但是使用起来太麻烦, 模板代码一大坨
4.Netty的编程模型
Netty在JavaNIO的基础上再套了一层, 抽象了自己的API, 这套API与平台无关,与协议无关; 使用的也是事件驱动的编程模型
4.1 事件
传统的线性编程思路是在一个线程中, 依次执行:
- 建立连接
- 读取数据(处理半包,粘包)
- 协议解码
- 组装报文
- 处理业务 (这一步不在Netty的EventLoop中执行)
- 接收返回值
- 拆解报文
- 协议编码
- 写入数据
- 断开连接
现在Netty的做法是把这些全部拆分开来, 每一步操作当作一个事件
只要是事件,就丢进EventLoop中处理
只要处理事件的代码没有耗时操作, 那么性能就能保持非常高的水准