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

简介: CPU密集型与I/O密集型是在计算机上执行任务的两种策略,在并发执行任务场景下,我们需要选择使用多线程或多进程;如果是IO密集型任务,使用多线程,线程越多越好;如果是CPU密集型任务,使用多进程,线程数量与CPU核心数匹配。
关于作者:CSDN内容合伙人、技术专家, 从零开始做日活千万级APP。
专注于分享各领域原创系列文章 ,擅长java后端、移动开发、人工智能等,希望大家多多支持。

一、导读

我们继续总结学习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学习专栏]

相关文章
|
3月前
|
机器学习/深度学习 缓存 监控
linux查看CPU、内存、网络、磁盘IO命令
`Linux`系统中,使用`top`命令查看CPU状态,要查看CPU详细信息,可利用`cat /proc/cpuinfo`相关命令。`free`命令用于查看内存使用情况。网络相关命令包括`ifconfig`(查看网卡状态)、`ifdown/ifup`(禁用/启用网卡)、`netstat`(列出网络连接,如`-tuln`组合)以及`nslookup`、`ping`、`telnet`、`traceroute`等。磁盘IO方面,`iostat`(如`-k -p ALL`)显示磁盘IO统计,`iotop`(如`-o -d 1`)则用于查看磁盘IO瓶颈。
210 10
|
1月前
|
并行计算 监控 数据处理
构建高效Python应用:并发与异步编程的实战秘籍,IO与CPU密集型任务一网打尽!
【7月更文挑战第16天】Python并发异步提升性能:使用`asyncio`处理IO密集型任务,如网络请求,借助事件循环实现非阻塞;`multiprocessing`模块用于CPU密集型任务,绕过GIL进行并行计算。通过任务类型识别、任务分割、避免共享状态、利用现代库和性能调优,实现高效编程。示例代码展示异步HTTP请求和多进程数据处理。
36 8
|
1月前
|
并行计算 数据处理 Python
Python并发编程迷雾:IO密集型为何偏爱异步?CPU密集型又该如何应对?
【7月更文挑战第17天】Python并发编程中,异步编程(如`asyncio`)在IO密集型任务中提高效率,利用等待时间执行其他任务。但对CPU密集型任务,由于GIL限制,多线程效率不高,此时应选用`multiprocessing`进行多进程并行计算以突破限制。选择合适的并发策略是关键:异步适合IO,多进程适合CPU。理解这些能帮助构建高效并发程序。
33 6
|
1月前
|
开发框架 并行计算 .NET
从菜鸟到大神:Python并发编程深度剖析,IO与CPU的异步战争!
【7月更文挑战第18天】Python并发涉及多线程、多进程和异步IO(asyncio)。异步IO适合IO密集型任务,如并发HTTP请求,能避免等待提高效率。多进程在CPU密集型任务中更优,因可绕过GIL限制实现并行计算。通过正确选择并发策略,开发者能提升应用性能和响应速度。
41 3
|
1月前
|
算法 Java 程序员
解锁Python高效之道:并发与异步在IO与CPU密集型任务中的精准打击策略!
【7月更文挑战第17天】在数据驱动时代,Python凭借其优雅语法和强大库支持成为并发处理大规模数据的首选。并发与异步编程是关键,包括多线程、多进程和异步IO。对于IO密集型任务,如网络请求,可使用`concurrent.futures`和`asyncio`;CPU密集型任务则推荐多进程,如`multiprocessing`;`asyncio`适用于混合任务,实现等待IO时执行CPU任务。通过这些工具,开发者能有效优化资源,提升系统性能。
52 4
|
1月前
|
并行计算 Java 大数据
深度探索:Python异步编程如何优雅征服IO密集型任务,让CPU密集型任务也臣服!
【7月更文挑战第17天】Python的异步编程借助`asyncio`库提升IO密集型任务效率,如并发下载网页,通过`async def`定义协程,`asyncio.gather`并发执行。在CPU密集型任务中,结合`ThreadPoolExecutor`实现并行计算,利用多核优势。`asyncio.run`简化事件循环管理,使Python在高负载场景下表现更佳。
34 4
|
1月前
|
分布式计算 并行计算 Java
Python并发风暴来袭!IO密集型与CPU密集型任务并发策略大比拼,你站哪队?
【7月更文挑战第17天】Python并发处理IO密集型(如网络请求)与CPU密集型(如数学计算)任务。IO密集型适合多线程和异步IO,如`ThreadPoolExecutor`进行网页下载;CPU密集型推荐多进程,如`multiprocessing`模块进行并行计算。选择取决于任务类型,理解任务特性是关键,以实现最佳效率。
34 4
|
1月前
|
开发框架 并行计算 .NET
脑洞大开!Python并发与异步编程的哲学思考:IO密集型与CPU密集型任务的智慧选择!
【7月更文挑战第18天】在Python中,异步编程(如`asyncio`)适合处理IO密集型任务,通过非阻塞操作提高响应性,例如使用`aiohttp`进行异步HTTP请求。而对于CPU密集型任务,由于GIL的存在,多进程(`multiprocessing`)能实现并行计算,如使用进程池进行大量计算。明智选择并发模型是性能优化的关键,体现了对任务特性和编程哲学的深刻理解。
22 2
|
1月前
|
UED 开发者 Python
Python并发编程新纪元:异步编程如何重塑IO与CPU密集型任务的处理方式?
【7月更文挑战第18天】Python异步编程提升IO任务效率,非阻塞模式减少等待时间,优化用户体验。asyncio库与await关键字助力编写非阻塞代码,示例展示异步HTTP请求。CPU密集型任务中,异步编程结合多进程可提升效率。异步编程挑战包括代码复杂性,解决策略包括使用类型提示、异步框架及最佳实践。异步编程重塑任务处理方式,成为现代Python开发的关键。
26 2
|
1月前
|
开发框架 并行计算 算法
揭秘Python并发神器:IO密集型与CPU密集型任务的异步革命,你竟还傻傻分不清?
【7月更文挑战第18天】Python并发编程中,异步IO适合IO密集型任务,如异步HTTP请求,利用`asyncio`和`aiohttp`实现并发抓取,避免等待延迟。而对于CPU密集型任务,如并行计算斐波那契数列,多进程通过`multiprocessing`库能绕过GIL限制实现并行计算。选择正确的并发模型能显著提升性能。
46 2