CPU-bound(计算密集型) 与 I/O-bound(I/O密集型)
Posted Lovnx
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CPU-bound(计算密集型) 与 I/O-bound(I/O密集型)相关的知识,希望对你有一定的参考价值。
前言
在一个技术交流群里面看到有人在问,如何设置应用的线程池大小?有人回复了说,不谈并发类型(计算密集型或者IO密集型)的话,这个问题纯属瞎扯淡。下面是一些个人理解与在网上看到的比较好的解释。
1、CPU-bound(计算密集型)
计算密集型是说需要这个应用的运行需要充分运用CPU资源,比如说Hadoop离线处理应用、Storm清洗项目、视频图片渲染等等,CPU运算资源都被用来进行逻辑计算,这里引发线程池问题其实是多核CPU的问世所引发的,因为CPU上下文切换多了不好,少了也不好,不多不少的那个值刚刚好,所以计算密集型的应用完全是靠CPU核数来工作并影响性能的,看到有一个方案比较好:
线程数 = CPU核数+1
//也可以设置成CPU核数*2,这还是要看JDK的使用版本,以及CPU配置(服务器的CPU有超线程)。对于JDK1.8来说,里面增加了一个并行计算,计算密集型的较理想线程数 = CPU内核线程数*2
有人写过一个例子来验证:
import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
/**
* 计算文件夹大小
*/
public class FileSizeCalc
static class SubDirsAndSize
public final long size;
public final List<File> subDirs;
public SubDirsAndSize(long size, List<File> subDirs)
this.size = size;
this.subDirs = Collections.unmodifiableList(subDirs);
private SubDirsAndSize getSubDirsAndSize(File file)
long total = 0;
List<File> subDirs = new ArrayList<File>();
if (file.isDirectory())
File[] children = file.listFiles();
if (children != null)
for (File child : children)
if (child.isFile())
total += child.length();
else
subDirs.add(child);
return new SubDirsAndSize(total, subDirs);
private long getFileSize(File file) throws Exception
final int cpuCore = Runtime.getRuntime().availableProcessors();
final int poolSize = cpuCore+1; //修改这里
ExecutorService service = Executors.newFixedThreadPool(poolSize);
long total = 0;
List<File> directories = new ArrayList<File>();
directories.add(file);
SubDirsAndSize subDirsAndSize = null;
try
while(!directories.isEmpty())
List<Future<SubDirsAndSize>> partialResults= new ArrayList<Future<SubDirsAndSize>>();
for(final File directory : directories)
partialResults.add(service.submit(new Callable<SubDirsAndSize>()
@Override
public SubDirsAndSize call() throws Exception
return getSubDirsAndSize(directory);
));
directories.clear();
for(Future<SubDirsAndSize> partialResultFuture : partialResults)
subDirsAndSize = partialResultFuture.get(100,TimeUnit.SECONDS);
total += subDirsAndSize.size;
directories.addAll(subDirsAndSize.subDirs);
return total;
finally
service.shutdown();
public static void main(String[] args) throws Exception
for(int i=0;i<10;i++)
final long start = System.currentTimeMillis();
long total = new FileSizeCalc().getFileSize(new File("e:/m2"));
final long end = System.currentTimeMillis();
System.out.format("文件夹大小: %dMB%n" , total/(1024*1024));
System.out.format("所用时间: %.3fs%n" , (end - start)/1.0e3);
需要做的就是把程序里的线程池大小进行修改,观察消耗的时间。
2、I/O bound(I/O密集型)
比如说一个后台管理系统,我们后端的接口都是用来做CURD的,这个时候就会涉及到网络传输,IO交互,造成的结果就是IO等待,线程等待。因为线程上下文切换也是有代价的,这个时候面临的问题就是如何设置线程池的合理大小,使得CPU尽量不处于空闲状态(线程等待是不占CPU的),尽量提高CPU利用率。下面是一个对于IO密集型应用线程池设置的公式:
线程数 = CPU核心数/(1-阻塞系数)
//这个阻塞系数一般为0.8~0.9之间,也可以取0.8或者0.9。套用公式,对于双核CPU来说,它比较理想的线程数就是20,当然这都不是绝对的,需要根据实际情况以及实际业务来调整。
线程池从根本上解决不了IO密集型应用的问题的,需要使用异步非阻塞的方式,如何让等待线程异步释放才是解决的关键,关于这一点,Netty做得很好。
以上是关于CPU-bound(计算密集型) 与 I/O-bound(I/O密集型)的主要内容,如果未能解决你的问题,请参考以下文章