[英]Best way to parallelize thousands of downloads
我正在创建一个应用程序,我必须使用 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 -> downloadAlbum() 方法中还有一个 parallelStream():
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 内核的机器。
假设每个相册有 1000 张图片,那么我需要并行下载 50000 张图片。
认为您的应用程序并行执行 50000 件事情是错误的。 您正在尝试做的是优化您的吞吐量 - 您正在尝试在最短的时间内下载所有图像。
您应该尝试一个固定大小的线程池,然后调整池中的线程数量,直到优化吞吐量——也许从处理器数量的两倍开始。 如果您的应用程序主要在等待网络或服务器,那么也许您可以增加池中的线程数,但您不希望服务器超载以使其缓慢爬行并且您不希望破坏您的应用程序有大量线程。
这将创建 5 个不同的池,每个池有 1000 个线程,这就像 5000 个线程可能会降低性能而不是提高性能。
除非每张专辑有不同的服务器,或者每张专辑的下载量不同的其他原因,否则我认为多个池没有意义。
使其“非常非常快”的唯一方法是获得与服务器的“非常非常快”的网络连接; 例如,将您的客户端与您正在下载的服务器放在一起。
您的下载速度将受到许多潜在瓶颈的限制。 这些包括:
服务器的性能; 即它可以以多快的速度组装数据以发送给您并通过其网络接口推送它。
服务施加的每用户请求限制。
客户端和服务器之间的网络路径的端到端性能。
您正在运行的机器在从网络移动数据并将其(我猜)放到本地磁盘方面的性能。
瓶颈可能是这些中的任何一个,或它们的组合。
在问题上投入数千个线程不太可能改善问题。 事实上,如果有的话,它可能会使性能不太理想。 例如:
一个更好的主意是使用带有小型有界工作池的 ExecutorService,并将下载作为任务提交到池中。 (并尝试在下载之间保持 HTTP / HTTPS 连接打开。)
我还建议您确保您有权做您正在做的事情。 音乐出版行业的公司拥有优秀的律师。 如果他们认为您违反了他们的条款和条件或窃取了他们的知识产权,他们可能会让您的生活变得不愉快1 。
1 - 比如阻止您的 IP 地址或向您的服务提供商发出删除请求。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.