CPU密集型和IO密集型任务的权衡:如何找到最佳平衡点
时间:2024-04-30 17:55:59 来源:网络cs 作者:康由 栏目:其他工具 阅读:
CPU密集型,也叫计算密集型。
系统运行时,CPU读写I/O(硬盘/内存)时可以在很短的时间内完成,几乎没有阻塞时间(等待I/O的实时间),而CPU一直有大量运算要处理,因此CPU负载长期过高。
CPU密集几乎无I/O阻塞,CPU一直会全速运行。如果是单核情况下,开多线程是没有意义的,一个CPU来回切着运行,增加线程切换的资源消耗。
可见,CPU密集任务只有在多核CPU上、开多线程才可能提速。
CPU使用率较高时(如我们训练算法模型、搞训练集),通常线程数只需要设置为CPU核心数的线程个数就可以了。
一般其计算公式可遵循:CPU密集型核心线程数 = CPU核数 + 1。《Java并发编程实践》这么说:计算密集型的线程恰好在某时因为发生一个页错误或者因其他原因而暂停,刚好有一个“额外”的线程,可以确保在这种情况下CPU周期不会中断工作。
特点:
进行大量的计算消耗CPU资源,较高的CPU占用率,比如计算圆周率、对视频进行高清解码等等,全靠CPU的运算能力。较少的IO操作3.2、I/O密集型
I/O密集型相反,听名字就知道,系统运行多是CPU在等I/O (硬盘/内存) 的读写操作,此类情景下CPU负载并不高。
I/O密集型的程序一般在达到性能极限时,CPU占用率仍然较低。
这可能是因为任务本身需要大量I/O操作,没有充分利用CPU能力,导致线程空余时间很多。
通常我们会开CPU核心数数倍的线程,在线程进行 I/O 操作 CPU 空闲时,启用其他线程继续使用 CPU,以提高 CPU 的使用率,充分利用CPU资源。
一般其计算公式可遵循:I/O密集型核心线程数 = (线程等待时间/ 线程CPU时间 + 1)* CPU数目。当然我们也看到有多种计算公式,但都不是最优解,具体情况需结合项目实际使用,配置合适的线程数
一般来说:文件读写、DB读写、网络请求等都是I/O密集型
特点:
高IO操作计算操作少CPU占用率低四、如何区分IO密集型、CPU密集型任务
我们需要知道某一个任务是否是CPU消耗型的任务(定容线程池),还是说IO类型的任务(缓存线程池),充分的调用CPU资源。
那在此之前,我们需要知道两个概念:
Wall Duration:代码执行时间(包括了running + runnable + sleep等所有时长)
比如我们要知道某方法执行时间,可以通过系统时间差即可:
void method() { long start = System.currentTimeMillis(); // 业务代码 long wallTime = System.currentTimeMillis() - start; }
CPU Duration: 代码消耗CUP的时间(重点指标,优化方向)。
void method() { long start = SystemClock.currentThreadTimeMillis(); //当前线程运行了多少时间(毫秒值,不含thread或systemclock.sleep的值) // 业务代码 long wallTime = SystemClock.currentThreadTimeMillis() - start; }
那如果在Android 端,我们借助SysTrace工具即可(具体方法可自行搜索),如下图
通过SysTrace查看 Wall Duration 与 CPU Duration,
消耗的CPU时间片较多,我们就把它定义为CPU消耗型的任务,放在定容线程池里调度(即线程数量固定)
消耗的时间片少,我们就把它定义为IO类型的任务,放在缓存线程池中。
缓存线程池(CachedThreadPool)是Java中的一种线程池类型。它是一种动态线程池,可以根据需要自动创建新的线程,并在线程空闲一段时间后销毁。以上是比较粗暴的分类方法,如果是混合型的任务,那就要慢慢调试,找个最佳数量。
五、 推荐阅读
Java 专栏
SQL 专栏
数据结构与算法
Android学习专栏
本文链接:https://www.kjpai.cn/news/2024-04-30/163810.html,文章来源:网络cs,作者:康由,版权归作者所有,如需转载请注明来源和作者,否则将追究法律责任!