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

CPU密集型和IO密集型任务的权衡:如何找到最佳平衡点

关于作者:CSDN内容合伙人、技术专家, 从零开始做日活千万级APP。
专注于分享各领域原创系列文章 ,擅长java后端、移动开发、人工智能等,希望大家多多支持。

目录

  • 一、导读
  • 二、概览
  • 三、CPU密集型与IO密集型
    • 3.1、CPU密集型
    • 3.2、I/O密集型
  • 四、如何区分IO密集型、CPU密集型任务
  • 五、 推荐阅读

一、导读

我们继续总结学习Java基础知识,温故知新。

二、概览

CPU密集型与I/O密集型是在计算机上执行任务的两种策略,在并发执行任务场景下,我们需要选择使用多线程或多进程;
如果是IO密集型任务,使用多线程,线程越多越好;
如果是CPU密集型任务,使用多进程,线程数量与CPU核心数匹配。

我们了解这些概念有助于在资源分配和性能优化等方面有很大的帮助。
我们在选择线程池的时候,我们需要知道某一个任务是否是CPU消耗型的任务,还是说IO类型的任务,以便充分的调用CPU资源。

三、CPU密集型与IO密集型

3.1、CPU密集型

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工具即可(具体方法可自行搜索),如下图
1
通过SysTrace查看 Wall Duration 与 CPU Duration,

消耗的CPU时间片较多,我们就把它定义为CPU消耗型的任务,放在定容线程池里调度(即线程数量固定)

消耗的时间片少,我们就把它定义为IO类型的任务,放在缓存线程池中。

  • 缓存线程池(CachedThreadPool)是Java中的一种线程池类型。它是一种动态线程池,可以根据需要自动创建新的线程,并在线程空闲一段时间后销毁。

以上是比较粗暴的分类方法,如果是混合型的任务,那就要慢慢调试,找个最佳数量。

五、 推荐阅读

Java 专栏

SQL 专栏

数据结构与算法

Android学习专栏

http://www.lryc.cn/news/95228.html

相关文章:

  • 超越POSIX:一个时代的终结?
  • 秋招算法备战第22天 | 654.最大二叉树、617.合并二叉树、700.二叉搜索树中的搜索、98.验证二叉搜索树
  • 小程序之移花宫-自定义底部标签图标---【浅入深出系列005】
  • 题目1 SQL注入(保姆级教程)
  • PDF转换成word乱码了怎么办?最实用的方法在这里!
  • 字节跳动后端面试,笔试部分
  • [JavaScript游戏开发] 2D二维地图绘制、人物移动、障碍检测
  • 区间预测 | MATLAB实现基于QRF随机森林分位数回归时间序列区间预测模型
  • .NET网络编程——TCP通信
  • 【Python机器学习】实验01 Numpy以及可视化回顾
  • vue3-组件中的变化
  • 认识主被动无人机遥感数据、预处理无人机遥感数据、定量估算农林植被关键性状、期刊论文插图精细制作与Appdesigner应用开发
  • 数学建模的六个步骤
  • 【计算机组成原理】24王道考研笔记——第二章 数据的表示和运算
  • JQ-6 Bootstrap入门到实战;Bootstrap的(优缺点、安装、响应式容器原理、网格系统、响应式工具类、Bootstrap组件);小项目实践
  • 如何用3D格式转换工具HOOPS Exchange读取颜色和材料信息?
  • [Ubuntu 22.04] 安装docker,并设置镜像加速
  • 如何使用GPT作为SQL查询引擎的自然语言
  • Servlet3.0上传文件
  • 【ARM Cache 系列文章 6 番外篇 – MMU, MPU, SMMU, PMU 差异与关系】
  • NetSuite ERP顾问的进阶之路
  • js 新浏览器打开页面
  • jmeter软件测试实验(附源码以及配置)
  • ZooKeeper原理剖析
  • 【算组合数】CF1833 F
  • Attention详解(自用)
  • pptx转pdf工具类
  • 2023华为OD统一考试(B卷)题库清单(持续收录中)以及考点说明
  • 论文笔记--Won’t Get Fooled Again: Answering Questions with False Premises
  • 【Django】include app_name和namespace的区别