【问题标题】:Best way to parallelize thousands of downloads并行化数千次下载的最佳方式
【发布时间】: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


【解决方案1】:

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

认为您的应用程序并行执行 50000 件事情是错误的。您正在尝试做的是优化您的吞吐量 - 您正在尝试在最短的时间内下载所有图像。

您应该尝试一个固定大小的线程池,然后调整池中的线程数量,直到优化吞吐量——也许从处理器数量的两倍开始。如果您的应用程序主要在等待网络或服务器,那么也许您可以增加池中的线程数,但您不希望服务器超载以使其缓慢爬行并且您不希望破坏您的应用程序拥有大量线程。

这将创建 5 个不同的池,每个池有 1000 个线程,这就像 5000 个线程可能会降低而不是提高性能。

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

【讨论】:

    【解决方案2】:

    使其“非常非常快”的唯一方法是获得与服务器的“非常非常快”的网络连接;例如将您的客户端与您从中下载的服务器放在一起。

    您的下载速度将受到许多潜在瓶颈的限制。其中包括:

    1. 服务器的性能;即它可以以多快的速度组装数据以发送给您并通过其网络接口推送。

    2. 服务施加的每用户请求限制。

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

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

    瓶颈可能是这些中的任何一个,或它们的组合。

    在问题上投入数千个线程不太可能改善问题。事实上,如果有的话,它可能会使性能不太理想。例如:

    • 它可能会阻塞您的网络链接,或者
    • 它可能会在您从中获取数据的服务器中触发反占用或反 DOS 防御。

    一个更好的主意是使用带有 small 有界工作池的 ExecutorService,并将下载作为任务提交到池中。 (并尝试在下载之间保持 HTTP / HTTPS 连接打开。)


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

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

    【讨论】:

      猜你喜欢
      • 2016-04-03
      • 1970-01-01
      • 1970-01-01
      • 2011-02-18
      • 2013-01-18
      • 2010-09-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多