多线程的认识

4/7/2020 java

# 多线程的由浅及深

进程:当一个程序进入内存中运行,就是一个进程。所以每个进程都有单独的分配内存。典型的特征就是进程的pid,可以通过kill命令杀死进程。比如运行的每个软件就是每个进程。

线程:进程的一个执行单位,也是CPU调度的基本单位。一个进程会有多条线程,线程共享进程的所有上下文环境,在多进程时,CPU会不断的切换线程来执行(同一时间cpu只会执行一个线程,但cpu的速度很快,给人同时执行的错觉)。比如QQ同时和多人聊天。

从CPU角度讲,进程就是包换上下文切换的程序执行时间总和 = CPU加载上下文+CPU执行+CPU保存上下文,线程共享进程的上下文环境,为更细粒度的CPU时间段

# 线程和哪些因素有关?

  1. CPU

在最开始介绍多线程《多线程的由浅及深》时,介绍到线程共享进程的上下文环境,为更细粒度的CPU时间段。所以线程数的确定和CPU有关。至于CPU的核数和线程数的关系,可以查看这篇文章:CPU的核心数、线程数的关系和区别。(多线程实际上是计算机多种资源的并行运用,跟CPU有几个核心是没什么关系的)

  1. IO

IO分为磁盘IO和网络IO。影响磁盘的关键因数是磁盘服务时间,即磁盘完成一个I/O请求所花费的时间,它由寻道时间、旋转延迟和数据传输时间三部分构成。衡量其关键指标,大致是IOPS、吞吐量等。影响网络IO的关键因素是服务器响应延时 + 带宽限制 + 网络延时 + 跳转路由延时 + 本地接收延时。

  1. 并行

多个cpu实例或者多台机器同时执行一段处理逻辑

  1. 并发

CPU不断切换线程来实现多路复用,以提升效率。通过cpu调度算法,看上去同时执行,实际上从cpu操作层面不是真正的同时。通常会用TPS或者QPS来反应这个系统的处理能力

任务的性质

  1. CPU密集型任务

要进行大量的计算,消耗CPU资源,比如计算圆周率、对视频进行高清解码等等,全靠CPU的运算能力。要最高效地利用CPU,计算密集型任务同时进行的数量应当等于CPU的核心数。

一般配置线程数=CPU总核心数+1 (+1是为了利用等待空闲)

  1. IO密集型任务

这类任务的CPU消耗很少,任务的大部分时间都在等待IO操作完成(因为IO的速度远远低于CPU和内存的速度)。常见的大部分任务都是IO密集型任务,比如Web应用。对于IO密集型任务,任务越多,CPU效率越高(但也有限度)。

一般配置线程数=CPU总核心数 * 2 +1

# 总结

根据并发编程网的《如何合理地估算线程池大小》一文中的提示, 最佳线程数目 = (线程等待时间与线程CPU时间之比 + 1)* CPU数目 所以线程等待时间所占比例越高,需要越多线程。线程CPU时间所占比例越高,需要越少线程 问题

  1. 是否使用线程池就一定比单线程效率高呢? 否。比如Redis(点击查看)。

  2. 并发编程网的一个问题: 2.1 高并发、任务执行时间短的业务怎样使用线程池?

线程池线程数可以设置为CPU核数+1,减少线程上下文的切换

2.2 并发不高、任务执行时间长的业务怎样使用线程池?

a)假如是业务时间长集中在IO操作上,也就是IO密集型的任务,因为IO操作并不占用CPU,所以不要让所有的CPU闲下来,可以适当加大线程池中的线程数目,让CPU处理更多的业务 b)假如是业务时间长集中在计算操作上,也就是计算密集型任务,线程池中的线程数设置得少一些,减少线程上下文的切换

2.3 并发高、业务执行时间长的业务怎样使用线程池? 并发高、业务执行时间长,解决这种类型任务的关键不在于线程池而在于整体架构的设计,看看这些业务里面某些数据是否能做缓存是第一步,增加服务器是第二步,以及线程池的设置。最后,业务执行时间长的问题,也可能需要分析一下,看看能不能使用中间件对任务进行拆分和解耦。 参考: 《线程池大小设置CPU的核心数、线程数的关系和区别,同步与堵塞完全是两码事》 《如何合理设置线程池大小》 《IO与CPU跟线程的关系》 《廖雪峰:python进程vs线程》

Last Updated: 8/25/2021, 2:35:45 PM
我再没见过 像你一般的星空
Seto