CPU密集型和IO密集型与CPU内核之间的关系

CPU密集型

简介

CPU密集型(CPU-bound)指的是计算过程中,系统的性能瓶颈主要受到中央处理器(CPU)性能的限制。这类任务需要大量的计算,而不是等待外部操作,如磁盘输入输出或网络通信。典型的CPU密集型任务包括复杂的数学计算、图形渲染、视频编码等,这些任务中CPU的计算能力是提高处理速度的关键因素。

特点

  1. 高CPU利用率:这些任务在执行期间会使得CPU的利用率接近或达到100%。
  2. 少量的I/O操作:与I/O密集型任务相比,CPU密集型任务不频繁地执行输入输出操作。
  3. 复杂的计算:涉及到复杂算法和数学运算,如加密解密、数据分析等。
  4. 并行能力:可以被分解为多个子任务,这些子任务可以在多核CPU上并行执行。
  5. 时间消耗:这些任务通常需要连续的、长时间的CPU周期来完成。

应用场景

  1. 科学计算:物理模拟、气候模型、分子建模等领域的计算通常是CPU密集型的。
  2. 数据分析:大数据处理和复杂的统计分析需要大量的CPU资源来处理和分析数据。
  3. 图形渲染:3D图形渲染、视频压缩和图像处理等任务需要大量的CPU计算。
  4. 加密:加密算法执行加密和解密操作,尤其是在区块链和安全领域。
  5. 编译器:源代码编译为机器代码或字节码的过程是CPU密集型的。
  6. 游戏:现代游戏中的物理引擎和AI计算通常需要大量的CPU资源。

在设计和部署CPU密集型应用时,开发者需要考虑如何最有效地利用CPU资源,包括代码优化、并行算法设计以及适当的硬件选择。

IO密集型

简介

IO密集型指的是系统的CPU性能相对硬盘、内存要好很多,此时,系统运作,大部分的状况是CPU在等IO (硬盘/内存) 的读写操作,因此,CPU负载并不高。

特点

  1. 频繁的磁盘操作:涉及大量的读写文件系统的操作,如数据库交互、文件处理等。
  2. 网络通信:需要频繁地进行网络请求和响应,如Web服务器处理HTTP请求。
  3. 等待时间长:程序执行过程中有大量时间花在等待外部数据的读取或发送上。
  4. CPU空闲:在等待I/O操作完成时,CPU可能处于空闲状态,CPU利用率不高。
  5. 并发处理:I/O密集型任务通常可以通过增加并发处理来提高效率,因为CPU可以在等待一个任务的I/O时处理其他任务的计算。

使用场景:

应用场景

  1. Web服务器:处理大量并发的客户端请求,主要是网络I/O操作。
  2. 文件处理应用:如日志分析工具,需要读取、写入和处理大量文件数据。
  3. 数据库应用:数据库的查询和事务处理通常涉及大量的磁盘I/O操作。
  4. 数据备份服务:需要读取和写入大量数据到存储设备。
  5. 客户端/服务器应用:客户端发送请求到服务器,服务器处理请求并返回响应,主要涉及网络I/O。

在处理I/O密集型任务时,通常会采用异步I/O、多线程或者事件驱动的编程模型来提高程序的性能和响应速度,因为这些模型可以帮助减少CPU的空闲时间,让CPU在等待I/O操作的同时可以处理其他任务。

核心线程数设定

很多人可能觉得把线程池配置越大越好!这是有问题的。并不是人多就能把事情做好,比如做奶茶,正常每个环节安排一个人,做一杯奶茶的效率会比一个人做好几个环境高。但是要是一个环节安排多个人,明明只要一人做就行了,但是抢着做,效率会变高吗?我想并不会。 线程数量过多的影响也是和我们分配多少人做事情一样,对于多线程这个场景来说主要是增加了上下文切换成本。

上下文切换:

多线程编程中一般线程的个数都大于 CPU 核心的个数,而一个 CPU 核心在任意时刻只能被一个线程使用,为了让这些线程都能得到有效执行,CPU 采取的策略是为每个线程分配时间片并轮转的形式。当一个线程的时间片用完的时候就会重新处于就绪状态让给其他线程使用,这个过程就属于一次上下文切换。概括来说就是:当前任务在执行完 CPU 时间片切换到另一个任务之前会先保存自己的状态,以便下次再切换回这个任务时,可以再加载这个任务的状态。任务从保存到再加载的过程就是一次上下文切换

上下文切换通常是计算密集型的。也就是说,它需要相当可观的处理器时间,在每秒几十上百次的切换中,每次切换都需要纳秒量级的时间。所以,上下文切换对系统来说意味着消耗大量的 CPU 时间,事实上,可能是操作系统中时间消耗最大的操作。

Linux 相比与其他操作系统(包括其他类 Unix 系统)有很多的优点,其中有一项就是,其上下文切换和模式切换的时间消耗非常少。

所以,只有设置合适的线程池大小才是最好的。

在《Java并发编程实战》这本书中,Brian Goetz 和其他合著者提供了一个更为细化的线程池大小的计算方法,它考虑到了任务的性质(计算密集型或者I/O密集型),并给出了一个经验公式:

N~threads~ = N~cpu~ x U~cpu~ x (1 + W/C)

Nthreads:最佳线程数

Ncpu:CPU核心数

Ucpu:CPU的使用率

W:线程等待I/O操作或者其他阻塞操作的时间。

C:线程执行计算任务的时间。

线程等待时间所占比例越高,需要越多线程。线程计算时间所占比例越高,需要越少线程。

我们可以通过 JDK 自带的工具 VisualVM 来查看 W/S 比例。

CPU 密集型任务的 W/S 接近或者等于 0,因此, 线程数可以设置为 Ncpu ∗(1+0)= Ncpu,和我们上面说的 Ncpu+1 差不多。

IO 密集型任务下,几乎全是线程等待时间,从理论上来说,你就可以将线程数设置为 2Ncpu(按道理来说,W/S 的结果应该比较大,这里选择 2N 的原因应该是为了避免创建过多线程吧)。

公示也只是参考,具体还是要根据项目实际线上运行情况来动态调整。

参考:

CPU 密集型 和 IO密集型 的区别,如何确定线程池大小?

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值