【发布时间】:2021-07-12 09:32:56
【问题描述】:
我正在创建一个应用程序,我必须在其中使用 Java 下载数千张图像(每张约 1 MB)。
我在 REST 请求中获取相册 URL 列表,每个相册包含多个图像。
所以我的请求看起来像:
[
"www.abc.xyz/album1",
"www.abc.xyz/album2",
"www.abc.xyz/album3",
"www.abc.xyz/album4",
"www.abc.xyz/album5"
]
假设每个相册有 1000 张图片,那么我需要并行下载 50000 张图片。
现在我已经使用parallelStream() 实现了它,但我觉得我可以进一步优化它。
有两个主要类 - AlbumDownloader 和 ImageDownloader(Spring 组件)。
所以主应用程序在专辑列表上创建了一个parallelStream():
albumData.parallelStream().forEach(ad -> albumDownloader.downloadAlbum(ad));
AlbumDownloader 中还有一个 parallelStream() -> downloadAlbum() 方法:
List<Boolean> downloadStatus = albumData.getImageDownloadData().parallelStream().map(idd -> imageDownloader.downloadImage(idd)).collect(Collectors.toList());
我正在考虑将CompletableFuture 与ExecutorService 一起使用,但我不确定应该使用什么池大小?
我应该为每个专辑创建一个单独的池吗?
ExecutorService executor = Executors.newFixedThreadPool(Math.min(albumData.getImageDownloadData().size(), 1000));
这将创建 5 个不同的池,每个池有 1000 个线程,这就像 5000 个线程可能会降低而不是提高性能。
你能给我一些想法让它变得非常非常快吗?
顺便说一句,我正在使用 Apache Commons IO FileUtils 下载文件,并且我有一台具有 12 个可用 CPU 内核的机器。
【问题讨论】:
-
您考虑过剖析吗?因为没有这样的神奇数字。
-
上限将由图像服务器的响应时间和您的互联网连接的下载带宽决定。 Java 的 NIO 有异步的东西,应该可以节省你的线程,但我认为你可以节省必要的线程来完全耗尽服务器容量或带宽。
-
我认为更好的方法是只并行化专辑而不是图像,如果它们太多,使用分页。此外,并行或堆栈获取 1000 个图像会更快吗?
-
@JohnyDeph - 我也想并行下载图像。考虑一个场景,我只传递了一张包含 5000 张图像的专辑。我不希望按顺序下载这 5000 张图像,对吗?每个图像下载都是与服务器的新连接(具有确切的图像 URL)加上将该图像保存到磁盘的过程的组合。
-
我没有看到任何问题,即使 10000 张图像将在一个线程中。好的 10000 个线程和 10000 个并行行为的连接。第一个问题:如果有多个具有相同并行行为的设备,您的数据源将如何处理?第二个问题:如果您的互联网连接太慢怎么办?你的并行化变得没用了,对吧?第三个问题:连接数据库,你应该为每个线程创建新的连接,你觉得可以吗?对不起,如果我错了
标签: java multithreading java-stream completable-future fileutils