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

  • 5
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值