2011-12-04 52 views
1

我有一個圖像上傳servlet,它通過HTTP POST接收上傳的圖像,並且是大小從5 MB到75 MB不等的高分辨率圖像。圖像數據從請求輸入流中讀取並保存到本地磁盤上。我正在尋找一種有效的機制來從請求輸入流中並行生成縮略圖(或部分連續的,如果不是完全平行的)不同大小(4-5種不同大小,其中最大的是webimage - 1024x768),並將流保存到磁盤作爲原始上傳的文件。從單個圖像流高效地生成多個縮略圖

我現在能想到的是,直到 -

  1. 保存原始流作爲圖像文件保存到磁盤。
  2. 生成webimage(1024x768),這是該批量縮略圖中最大的一個。
  3. 然後用它來生成後續較小的圖像,因爲它會更快。

有人能請建議一個更好的有效方法嗎?最理想的方法是同步執行此操作,但如果非常有效,異步也很好。

在這方面的任何幫助將非常讚賞用Jav​​a。

回答

0

這是一個非常有趣的問題,因爲它有很多優化點。

關於生成一個較小的圖像然後生成縮略圖的想法可能是一個很好的想法,但我要說的第一件事是,如果你有一個75MB的圖像,那麼它顯然比1024x768大得多 - 最有可能的幾倍在這種情況下,您希望確保使用SCALE_FAST縮放圖像(Image)。你想要實現的是縮放比例縮小圖像,通過丟棄像素而不是嘗試做更好看的(並且更昂貴的)區域平均等任何事情。您甚至可以通過抓住圖像的int []並對每個第N個元素進行採樣,以便爲新圖像創建一個新的int [],並以某種因子縮小比例,從而使其更快。

在這一點上,你將有一個較小的圖像,說2000年大約2000年。然後,你可以採取該圖像和縮放它使用更好的尋找像SCALE_SMOOTH實際縮略圖。

我會說,你應該而不是如果可能的話(無論如何處理)寫入磁盤。如果你可以在內存中執行操作,它將會更快,並且在並行性的情況下是非常重要的。除非您的服務器正在運行SSD,然後同時運行兩個磁盤繁重的操作(例如其中兩個圖像被同時重新縮放或者一個圖像被重新縮放到兩個不同的大小)將會強制磁盤出現顛簸(因爲主軸一次只能讀取一個流)。然後,你將受到你尋求時間的控制,你很快就會發現,連續化所有的操作將比一次完成多個操作要快得多。

我會說他們在內存中重新調整它們,然後將它們寫入(同步)到ArrayList,然後讓另一個線程順序讀取這些圖像並存儲它們。如果你不知道我在說什麼,然後看看我的回答另一個問題在這裏:

Producer Consumer solution in Java

這樣你parallelise其中的有用(CPU運算)和你做的文件順序寫入(避免顛簸)。

話雖如此,你需要問自己,如果並行將會使你受益。你的服務器是否有多個CPU /內核?如果不是,那麼這是毫無意義的,你應該不會打擾任何東西,因爲它只會讓你失去時間。

此外,如果您希望一次上傳很多這些圖像,那麼您可能不需要平行處理每個圖像,因爲您將最終獲得多個網絡服務器線程,每個線程最多處理一個圖像的時間,無論如何,這將爲您在多個核心上提供良好的CPU利用率。例如,如果您期望在任何時候都會有4個圖像不斷上傳,那麼這將使用4個內核,而不需要進一步的並行處理。

最後一點需要注意的是,當您重新調整圖像尺寸時,一旦擁有了中間圖像,您可以將之前的圖像設置爲空以方便垃圾收集,這意味着當您生成縮略圖時,內存,而不是原來的大尺寸。

0

讓我看看,如果我得到這個權利,

你有一個大的圖像,並希望在同一時間就可以執行不同的操作。一些操作涉及磁盤IO。

選項1 啓動1個線程將原始hi res圖像保存到磁盤。與其他操作相比,這會花費很長時間,因爲磁盤寫入速度很慢。 開始其他線程創建所需大小的縮略圖。您需要調整原始圖像的大小。我相信這可以通過克隆原始圖像的字節來完成(在java中,我假設BufferedImage)。然後,您可以根據您希望的尺寸調整克隆大小。調整大小操作比寫入磁盤更快。

如果每個縮略圖有1個線程,則可以使用這些線程將其縮略圖保存到磁盤。問題在於你會快速製作縮略圖,並且所有這些線程幾乎一次寫入磁盤。這裏的問題是它們可能被髮送到不同的磁盤位置,而不是被分組到磁盤上的同一物理區域(局部性問題)。結果是,磁盤寫入將比不併行地執行此操作慢,因爲磁盤必須尋找新的位置並寫入一些數據,然後CPU執行上下文切換並接受另一個將寫入另一個部分的線程的磁盤(所以另一個尋求)等。所以這個想法很慢。

注意:使用具有線程池的ExecutorService,而不是單個線程。在我的例子中,我爲每個縮略圖使用了1個線程,因爲它使得它更容易解釋。

選項2, 你可以做的另一種方式是指定一個線程做寫盤,和其他幾個工作線程做調整。將所有thmubnails緩存到一個列表中,寫入磁盤的線程將把它們一個接一個地寫出來。

選項3, 最後,如果你有多個磁盤,你可以給每個線程的磁盤寫入,那麼所有寫入將在平行(或多或少)。

如果您有RAID,寫入速度會更快,但速度並不像上面剛剛提到的那麼快,因爲文件並非以並行方式串行寫入。 RAID將同一文件的一部分寫入並行化(一次寫入不同的磁盤)。