Redis教程
Contents
响应式变成与虚拟线程
平台线程
- 平台线程是操作系统的一个线程,大概有以下特点:
- 需要1ms来启动
- 会被预先分配约2m内存
- 上下文切换需要0.1ms
- 内存的分配与操作系统的实现保持一致:
- 在线程创建时,操作系统在虚拟内存中为线程栈预留空间。
- 物理内存分配:实际物理内存往往是按需分配的,当访问栈空间时,出发缺页异常,通过页错误(page fault)机制实现
- 当线程第一次访问其栈空间的某个页面时,操作系统才会为该页面分配物理内存(懒加载方式)
- 内存的大小制约了cpu的处理请求数量
给定条件:
- CPU频率:3.5 GHz (3.5 × 10^9 Hz)
- 每个请求处理耗时:0.1 ms (0.0001 秒)
从纯频率角度计算理论处理能力:
- 每秒钟CPU可执行的周期数 = 3.5 × 10^9 周期/秒
- 每个请求需要的CPU周期数 = 0.1 ms × 3.5 × 10^9 Hz = 0.0001 秒 × 3.5 × 10^9 周期/秒 = 3.5 × 10^5 周期
- 每秒可处理的请求数 = CPU每秒周期数 ÷ 每请求所需周期数 = (3.5 × 10^9) ÷ (3.5 × 10^5) = 10^4 = 10,000 请求/秒
如果内存只有4G,实际上只能创建2048个平台线程,制约了cpu的处理速度
两种解决方案
异步响应式编程
- 异步响应式编程,让每个线程不是一直阻塞等待,充分利用cpu的速度,阻塞的事情可以异步来处理
然而响应式编程存在一定的问题,考虑如下代码:
|
|
上述代码通过异步处理两个方法,实现了整体耗时的下降,但其存在如下问题:
- 更多的线程被阻塞(平台线程):上述代码实际上阻塞了三个线程,两个是线程池的线程,一个是平台线程
- debug困难:不能定位到哪个线程出现问题。
- loose threads:如果f1因为某种原因,触发异常,则会导致f2永远不执行get(),es线程出会有一个线程什么都不做,永远被阻塞,不能将它用于其他任何事情。
虚拟线程
- 虚拟线程资源占用比平台线程更小
- 阻塞虚拟线程不会阻塞平台线程
- 虚拟线程并不能提供比响应式编程更快的代码,但可以尽情编写阻塞式代码
- 虚拟线程可以解决平台线程被阻塞的问题,因为可以随便阻塞虚拟线程,阻塞后其就被回收
- 虚拟线程可以解决难以调试的问题,对虚拟线程运行的代码打断点,实际上是可以看到错误堆栈的
参考如下代码:
|
|
结构化并发
- 结构化并发实际创建了一个资源块,资源块中每个都是并行处理
- 结构化并发块运行完(因为错误/完全运行结束)后,统一释放虚拟线程资源,清理仍在运行的thread,并将他们kill掉
- 结构化并发可以解决loose thread问题,因为会被杀掉
参考如下代码:
|
|
总结
虚拟线程实际上不能提供比响应式编程更快的速度(除非响应式变成并没有用好),实际上是解决了响应式编程的问题
- 更轻量级的阻塞处理(避免阻塞平台线程)
- 更好的debug模式
- 解决loose thread问题