Java 并行化数千次下载的最佳方法

Java 并行化数千次下载的最佳方法,java,multithreading,java-stream,completable-future,fileutils,Java,Multithreading,Java Stream,Completable Future,Fileutils,我正在创建一个应用程序,在这个应用程序中,我必须使用Java下载数千个图像(每个图像约1 MB) 我在REST请求中获取相册URL列表,每个相册包含多个图像 所以我的请求看起来像: [ "www.abc.xyz/album1", "www.abc.xyz/album2", "www.abc.xyz/album3", "www.abc.xyz/album4", "www.abc.xyz/a

我正在创建一个应用程序,在这个应用程序中,我必须使用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
(弹簧组件)

因此,主应用程序在相册列表上创建一个
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());
这将创建5个不同的池,每个池包含1000个线程,相当于5000个线程,这可能会降低性能,而不是提高性能

你能给我一些想法使它非常非常快吗

顺便说一下,我正在使用ApacheCommonsIO
FileUtils
下载文件,我有一台有12个可用CPU内核的机器

假设每个相册都有1000张图片,那么我需要并行下载50000张图片

认为应用程序并行处理50000件事情是错误的。你要做的是优化你的吞吐量——你要在最短的时间内下载所有的图片

您应该尝试使用一个固定大小的线程池,然后调整池中的线程数量,直到优化吞吐量为止——可能从双倍处理器数量开始。如果您的应用程序主要在等待网络或服务器,那么您可能可以增加池中的线程数,但您不想让服务器过载,从而使其变慢为爬行,也不想让大量线程重击您的应用程序

这将创建5个不同的池,每个池包含1000个线程,相当于5000个线程,这可能会降低性能,而不是提高性能

我认为多个池没有任何意义,除非每个相册都有不同的服务器,或者每个相册的下载量不同的其他原因。

使其“非常非常快”的唯一方法是与服务器建立“非常非常快”的网络连接;e、 g.将您的客户端与您正在下载的服务器共同定位

您的下载速度将受到许多潜在瓶颈的限制。这些措施包括:

  • 服务器的性能;i、 e.它能以多快的速度组合数据发送给您,并通过其网络接口推动数据

  • 服务施加的每用户请求限制

  • 客户端和服务器之间的网络路径的端到端性能

  • 您正在运行的机器在从网络移动数据并将其(我猜)放到本地磁盘方面的性能

  • 瓶颈可能是其中任何一个,也可能是它们的组合

    在这个问题上抛出数千个线程不太可能改善情况。事实上,如果有什么不同的话,它可能会使性能变得不太理想。例如:

    • 它可能会阻塞您的网络链接,或者
    • 它可能会在您从中获取的服务器中触发反占用或反DOS防御
    一个更好的主意是使用一个带有小型有界工作池的ExecutorService,并将下载作为任务提交到该池。(并尝试在下载之间保持HTTP/HTTPS连接打开。)


    我还建议你确保你有权限做你正在做的事情。从事音乐出版业务的公司都有优秀的律师。如果他们认为你违反了他们的条款和条件或窃取了他们的知识产权,他们可能会让你的生活变得不愉快


    1-例如阻止您的IP地址或向您的服务提供商发出删除请求。

    您考虑过配置文件吗?因为没有这样的神奇数字。上限将由图像服务器的响应时间和internet连接的下载带宽决定。Java的NIO具有异步功能,可以让您节省线程,但我认为您可以节省必要的线程,以完全耗尽服务器容量或带宽。我认为更好的方法是只并行相册而不是图像,如果它们太多,请使用分页。此外,并行或堆栈方式获得1000张图像的速度更快吗?@JohnyDeph-我也想并行下载这些图像。考虑一个场景,我只通过一张包含5000张图像的专辑。我不想让那5000张图片按顺序下载,对吗?每次图像下载都是一个到服务器的新连接(具有确切的图像URL)加上将该图像保存到磁盘的过程的组合。我看不出有任何问题,即使一个线程中有10000个图像。Ok 10000个线程,10000个连接,具有并行行为。第一个问题:如果有多个设备具有相同的并行行为,那么您的数据源将如何?第二个问题:如果你的互联网连接太慢怎么办?你的并行化变得没用了,对吧?第三个问题:连接到数据库,您应该为每个线程创建新的连接,您认为可以吗?对不起,如果我错了
    ExecutorService executor = Executors.newFixedThreadPool(Math.min(albumData.getImageDownloadData().size(), 1000));