Java中多线程下载图片并压缩能提高效率吗
作者:马男波杰克 发布时间:2023-08-06 07:40:10
目录
前言
实现思路
实测
前言
需求 导出Excel:本身以为是一个简单得导出,但是每行得记录文件中有一列为图片url,需要下载所有记录行对应得图片,然后压缩整个文件夹。
这里只做4.5.得代码讲解描述,其它也没什么好说得,话不多说上代码.
实现思路
多线程实现使用了线程池,Jdk1.8并发包下的CompletableFuture
第一步:得到基础数值
// 线程数
Integer threadNum = 10;
// 每条线程需要处理的图片数
int dataNum = imageInfoVos.size() / threadNum;
// 写入线程数
List<Integer> threadS = new ArrayList<>();
for(int i=0; i<threadNum; i++){
threadS.add(i);
}
首先我们保存了需要下载的图片的Url列表,多线程的方式下载我们需要保证每个线程下载的图片不会重复,因此我们需要根据规则来切割保存Url列表的集合,从而保证每个线程下载属于自己的任务,上代码:
// 接上文代码
threadS.stream().map(item -> CompletableFuture.runAsync(() ->{
List<Image> theadItem = imageInfoVos.subList(dataNum * item,(item+1)==threadNum?imageInfoVos.size():Math.min(dataNum * (item + 1 ), imageInfoVos.size()));
threadDownPic(theadItem,item,dirName);
},threadPoolTaskExecutor)).collect(Collectors.toList()).forEach(item ->{
try {
item.get();
}catch (Exception e){
log.error("============ 多线程down执行等待异常 msg:{} =============", e.getMessage());
}
});
这里进行拆分讲解
使用CompletableFuture.runAsync 走异步方式,遍历item
如item=10,也就是线程数为10,则直接执行10次(有线程池的前提下
)
// 使用CompletableFuture.runAsync 走异步方式,遍历item
// 如item=10,也就是线程数为10,则直接执行10次(有线程池的前提下)
threadS.stream().map(item -> CompletableFuture.runAsync(() ->{
规则:
根据item数值通过sublist 从开始到结束,截取对应线程所需要下载的Url列表
例:dataNum为每个线程需要完成的下载数如上文 dataNum为100时
如:item=0 dataNum* item(0) =0,Math.min(dataNum * (item + 1 )=100
(item+1)==threadNum?imageInfoVos.size() 此次是为了保证最后一个线程处理最后不足的图片
根据如上规则即可得到每个线程需要下载的图片Url保证不会重复
// 根据item数值通过sublist 从开始到结束,截取对应线程所需要下载的Url列表
// 例:dataNum为每个线程需要完成的下载数如上文 dataNum为100时
// 如:item=0 dataNum* item(0) =0,Math.min(dataNum * (item + 1 )=100
// 根据如上规则即可得到每个线程需要下载的图片Url保证不会重复
// (item+1)==threadNum?imageInfoVos.size() 此次是为了保证最后一个线程处理最后不足的图片
List<ImageInfoVo> theadItem = imageInfoVos.subList(dataNum * item,(item+1)==threadNum?imageInfoVos.size():Math.min(dataNum * (item + 1 ), imageInfoVos.size()));
// theadItem:图片Url item:所属下标 dirName:写入路径url
threadDownPic(theadItem,item,dirName);
由于执行的异步方式,此处是为了线程池中所有线程都结束才能往下走,执行压缩文件步骤,这里提一嘴,如果没有手动赋予线程池,CompletableFuture默认使用ForkJoinPool.commonPool,会根据电脑核心数来指定,
比如:我本机未指定就是7个线程,执行方法时,会执行完前面7个线程任务,才会继续创建3个线程继续执行后续未完成的
},threadPoolTaskExecutor)).collect(Collectors.toList()).forEach(item ->{
try {
item.get();
}catch (Exception e){
log.error("============ 多线程down执行等待异常 msg:{} =============", e.getMessage());
}
});
实测
主要代码也写完了,这种方式真的能提高效率吗?下面我贴几张测试图来说明
其实这种方式并没有显著的提高效率,当然这是我本机环境测试的。
效率是由网速决定,而不是由本机Cpu和io决定,比如10M带宽,一个线程一个一个顺序下载,但速度是10M,10个线程,可能每个线程的速度是1M,结果没有什么两样。
相对于网速,多线程带来的cpu以及io节省的时间几乎可以忽略,瓶颈还是在网速.
来源:https://juejin.cn/post/6976454072685559822


猜你喜欢
- 看了这个排行榜, 小编只想说:流水的编程语言,铁打的Java,C/C++!!人工智能的前景已经不用多说了,越来越多的人看重人工智能的前景,想
- 为什么要使用路由在之前我们的代码中,页面跳转使用的代码如下所示:Navigator.of(context).push( Mate
- 这篇文章主要介绍了java加载property文件配置过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,
- 一、前言虽然jdk1.9版本已经问世,但是许多其他的配套设施并不一定支持jdk1.9版本,所以这里仅带领你配置jdk1.8。而jdk1.9的
- 下面一段内容有项目需求有项目分析,通过一个小demo给大家展示下C#如何对多线程、多任务管理的。项目需求:假设多个任务需要执行,每个任务不是
- 在使用Java集合的时候,都需要使用Iterator。但是java集合中还有一个迭代器ListIterator,在使用List、ArrayL
- 本文实例讲述了C#日期格式字符串的相互转换操作。分享给大家供大家参考,具体如下:方法一:Convert.ToDateTime(string)
- spring-boot-maven-plugin:打包时排除provided依赖spring-boot-maven-plugin 插件提供s
- 前言👉本文中所有的代码和运行结果都是在amazon corretto openjdk 1.8环境中的,如果你不是使用该环境,可能会略有偏差。
- 下面我给各位朋友整理了一篇C# 获取图片文件扩展名的例子,这里方法都非常的简单,我们只用到了image.RawFormat.Guid就实现了
- 概念里氏替换原则是任何基类出现的地方,子类一定可以替换它;是建立在基于抽象、多态、继承的基础复用的基石,该原则能够保证系统具有良好的拓展性,
- 目录为什么要使用 TaskTask 和 Thread 区别Task 介绍Task 简单实现Task 执行状态1.等待(Wait)2. 返回值
- 介绍什么是ThreadLocal?ThreadLocal叫做线程变量,用于在多线程环境下创建线程本地变量。通俗的讲,ThreadLocal可
- 本文实例讲述了C#实现导入CSV文件到Excel工作簿的方法。分享给大家供大家参考。具体如下:你必须在项目中添加对 Microsoft.Of
- 前言这是几个月前写的博文,睡前看了觉得有些敷衍,还是改了再发吧。之前的博客做了个锁屏应用,在以前各种酷炫的锁屏效果是很流行的,有时候会去锁屏
- 为了解决在多个窗口之间的传值问题,我们可以通过设置静态类和静态变量的办法来实现窗口间值的传递窗体一代码//窗体1的代码using Syste
- 在value目录下,创建styles.xml文件<?xml version="1.0" encoding=&quo
- 一、代码结构:二、数据实体类:using System;using System.Collections.Generic;using Sys
- 目录时间轴是前端UI经常用到的效果,先看下效果图:实现一、借助 Container 中 decoration 属性,设置左侧的 border
- 装箱(boxing)和拆箱(unboxing)是C#类型系统的核心概念.是不同于C与C++的新概念!,通过装箱和拆箱操作,能够在值类型和引用