[英]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.