当前位置: 首页 > article >正文

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

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

一、CPU密集型

  1. 介绍

    CPU密集型,也叫计算密集型,是指需要大量CPU计算资源,例如大量的数学运算、图像处理、加密解密等。这种类型的任务主要依赖于CPU的计算能力,会占用大量的CPU时间片,使得CPU内核在执行任务时负载较重。CPU密集型任务在执行过程中主要消耗CPU资源,而对IO操作的需求相对较少。

  2. 与CPU内核的关系

    CPU密集型任务与CPU内核之间的关系在于任务的执行方式和CPU资源的利用。CPU密集型任务需要大量的CPU计算资源,通常会占用大量的CPU时间片,使得CPU内核在执行任务时负载较重。在多核处理器系统中,如果任务可以充分利用所有的CPU内核,那么整体的计算性能会得到提升。

    在自定义线程池中可以设置 核心线程数=CPU内核数+1,在处理CPU密集型任务时,通常希望充分利用系统中的所有CPU内核,同时避免线程频繁地创建和销毁带来的开销。根据经验,将核心线程数设置为CPU核数加1可以在大多数情况下达到比较好的性能表现。

    设置核心线程数为CPU核数加1的原因是为了确保在系统负载较重的情况下,仍然有一个空闲的线程可以立即执行任务,从而避免因线程创建和销毁带来的性能损失。这样可以更好地利用系统的计算资源,提高CPU密集型任务的执行效率。

  3. 代码测试

    public class CPUAndIOTest {
        public static void main(String[] args) {
            int availableProcessors = Runtime.getRuntime().availableProcessors();
            System.out.println("CPU内核数:" + availableProcessors);
    
            // 测试CPU密集型任务
            testCPUIntensiveTask(availableProcessors);
        }
    
        private static void testCPUIntensiveTask(int availableProcessors){
            long startTime = System.currentTimeMillis();
            int taskCount = 100; // 任务数量
            int corePoolSize = availableProcessors + 1;
            ExecutorService executor = Executors.newFixedThreadPool(corePoolSize);
            for (int i = 0; i < corePoolSize; i++) {
                try {
                    Thread.sleep(50);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                executor.execute(() -> {
                    // 模拟CPU密集型任务
                    double result = 0;
                    for (int j = 0; j < taskCount/corePoolSize; j++) {
                        try {
                            Thread.sleep(50);
                        } catch (InterruptedException e) {
                            throw new RuntimeException(e);
                        }
                        result += Math.random();
                    }
                });
            }
            executor.shutdown();
            while (!executor.isTerminated()) {
            }
            long endTime = System.currentTimeMillis();
            System.out.println("CPU密集型任务执行时间:" + (endTime - startTime) + "ms");
        }
    }
    

    模拟执行总量相同的CPU密集型任务,通过修改核心线程数,看看执行时间是多少,得出的结果如下

    核心线程数corePoolSize = 1时

    image-20231207210345776

    核心线程数corePoolSize = availableProcessors + 1也就是CPU内核数加1时

    image-20231207210448524

    核心线程数corePoolSize = availableProcessors * 2也就是CPU内核数*2时

    image-20231207210537937

    结果差不多如预期一样,当核心线程数=CPU内核数加1时执行时间要比另外2种更短,效率更高。

二、IO密集型

  1. 介绍

    IO密集型,是指需要大量的IO操作,例如文件读写、网络通信、数据库访问等。这种类型的任务主要涉及大量的IO操作,而CPU的计算能力相对较少。在执行IO密集型任务时,CPU内核的负载相对较轻,因为大部分时间都用于等待IO操作完成。IO密集型任务的性能瓶颈通常在于IO操作的速度和延迟,而不是CPU的计算能力。

  2. 与CPU内核的关系

    IO密集型任务与CPU内核之间的关系在于任务的执行方式和对系统资源的需求。IO密集型任务通常需要大量的IO操作,例如文件读写、网络通信、数据库访问等,而对CPU计算资源的需求相对较少。

    在自定义线程池中可以设置 核心线程数=CPU内核数*2,在处理IO密集型任务时,通常会出现大量的IO等待时间,而不是CPU计算时间。在这种情况下,可以充分利用系统中的多个CPU内核来处理其他线程的计算任务,从而提高系统的整体性能。

    将核心线程数设置为CPU核数的两倍的原因是为了确保在执行IO密集型任务时,系统能够充分利用CPU内核来处理其他线程的计算任务,同时保持足够的线程数量来处理IO操作。这样可以更好地利用系统的资源,提高IO密集型任务的执行效率。

  3. 代码测试

    public class CPUAndIOTest {
        public static void main(String[] args) {
            int availableProcessors = Runtime.getRuntime().availableProcessors();
            System.out.println("CPU内核数:" + availableProcessors);
    
            // 测试IO密集型任务
            testIOIntensiveTask(availableProcessors);
        }
    
        private static void testIOIntensiveTask(int availableProcessors) {
            long startTime = System.currentTimeMillis();
            int corePoolSize = availableProcessors * 2;
            ExecutorService executor = Executors.newFixedThreadPool(corePoolSize);
            for (int i = 0; i < corePoolSize; i++) {
                executor.execute(() -> {
                    // 模拟IO密集型任务
                    try {
                        Thread.sleep(5000/corePoolSize);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                });
            }
            executor.shutdown();
            while (!executor.isTerminated()) {
            }
            long endTime = System.currentTimeMillis();
            System.out.println("IO密集型任务执行时间:" + (endTime - startTime) + "ms");
        }
    }
    

    结果如下

    核心线程数corePoolSize = 1时

    image-20231207211624930

    核心线程数corePoolSize = availableProcessors + 1也就是CPU内核数加1时

    image-20231207211638205

    核心线程数corePoolSize = availableProcessors * 2也就是CPU内核数*2时

    image-20231207211648650

从以上的结果可以看出,随着线程数的增加,IO密集型任务执行时间会逐渐变短,但线程过多也会导致线程的大量切换,造成资源的浪费,所以一般IO密集型任务设置的核心线程数为CPU内核数*2。

三、总结

  1. CPU密集型:

    核心线程数=CPU内核数+1

  2. IO密集型:

    核心线程数=CPU内核数*2


http://www.kler.cn/a/162109.html

相关文章:

  • 标准C++ 字符串
  • OpenGL ES 共享上下文实现多线程渲染
  • 微服务(二)
  • C++初阶:类和对象(上)
  • 系统上线后发现bug,如何回退版本?已经产生的新业务数据怎么办?
  • jmeter常用配置元件介绍总结之定时器
  • Fabric 画布缩放、拖动、初始化大小
  • 人工智能_机器学习059_非线性核函数_poly核函数_rbf核函数_以及linear核函数效果对比---人工智能工作笔记0099
  • Docker快速入门(编译源码辅助技)
  • AWS攻略——使用中转网关(Transit Gateway)连接同区域(Region)VPC
  • Android 默认打开应用的权限
  • bat脚本之加法
  • Linux_vi/vim编辑器
  • Qt基础之四十:Qt Installer Framework(QtIFW)的编译、使用和实现原理
  • 【Python系列】Python函数
  • 经验分享|MySQL分区实战(RANGE)
  • 系列学习前端之第 4 章:一文精通 JavaScript
  • 【开源视频联动物联网平台】J2mod库写一个Modbus TCP 服务器
  • 在Arch Linux上安装yay
  • Tair(1):Tair介绍
  • vue2-使用vue-i18n搭建多语言切换环境
  • gitlab-jenkins-shell-helm-chart-k8s自动化部署微服务
  • CopyOnWriteArraySet怎么用
  • 用户管理 --汇总
  • C#无标题栏窗体拖动方法
  • C#-数组池减少GC工作