2010-10-13 55 views
2

我試圖提高在Linux上運行的Web應用程序中驗證碼圖像呈現的性能。看看目前使用的是什麼,我發現瓶頸在於使用Java2D,特別是Graphics2D類。如何讓圖像生成在Java上可擴展?

問題不在於執行速度,而在於可擴展性。基本上它不會縮放。在1個線程或2個線程中繪製驗證碼圖像在執行時間方面沒有任何改進。

作爲一個例子,你可以看看下面這個爲captcha圖像創建背景的類。這個問題上的調用出現的Graphics2D ::的setColor()和Graphics2D的::的drawLine():

http://www.docjar.com/html/api/com/octo/captcha/component/image/backgroundgenerator/FunkyBackgroundGenerator.java.html

一些google搜索後,我發現其中的話題說的Java2D是不是特別多線程(對不起,不允許給出多個鏈接:)但是,如果google爲'java2d multithreading',那麼你可以很容易地找到該主題,這將是第一個結果)

我相信必須有一些庫提供繪圖功能沒有找到它:(或Java2d,可能,可以切換到某種模式,這不會阻止對圖形對象的訪問(順便說一下,無頭模式並沒有幫助)。

我會很感激任何建議。事先,感謝您的答案。

+0

FWIW第一次打我時得到google搜索是關於寫來自多個線程的相同graphics2D對象。不是關於每個人都有自己的情況。 – wds 2010-10-13 11:47:18

+0

http://forums.sun.com/thread.jspa?threadID=5415900這裏是引語 - 「經過一些Google搜索後,我發現這篇四年前的文章談論java的OGL管道,只允許在單個線程上呈現(如java 1.6)。」 – Stas 2010-10-13 17:25:45

回答

1

沒有一種快速的方式可以共享Graphics2D,它的工作原理是可以預測的,因爲除非你有辦法對每個像素進行同步和重新排序,否則這將是一個巨大的競爭條件。

無論如何,您的Graphics2DBufferedImage支持,所以這可能是什麼讓你放緩。這是一個非加速表面,所以繪圖總是很慢。如果你的渲染服務器有圖形硬件(它確實應該是這樣的應用程序),你可以使用一個VolatileImage,這個數量比我的經驗中的BufferedImage要快一個數量級或兩個數量級。否則,你必須把你的背景世代切片成一個網格,AffineTransform他們所有的排隊,使所有網格元素的「隨機性」通過播種,將它們拼湊在一起並希望copyArea(...)方法足夠快,可以爲您提供改進。我幾乎可以說這是一個混亂,硬件加速是一條路。

您還應該考慮將其中的大量預渲染爲離線,並根據需要提供它們。這樣的話,除非在服務器空閒時間內不能滿足需求,否則性能或多或少不是問題(在這種情況下,您需要新硬件,只需製作一個硬件加速渲染盒)。

+0

感謝您的回覆並感謝您的建議。我會盡量使用它們使其稍微快一點。但看看源代碼,我給了一個鏈接。這些在Graphics對象上調用的方法除了在位置放置彩色像素之外沒有任何其他的作用。在圖形硬件上加速這樣的事聽起來很可笑。還有一點是,服務器在某個刀片服務器上運行,我不知道該盒子在哪個地理位置,甚至可能根本就不是一個物理盒子。 – Stas 2010-10-13 17:22:53

+0

理想的解決方案是一個庫,它可以在沒有任何圖形卡的情況下處理圖像,但是找不到它:( – Stas 2010-10-13 17:24:28

+0

@Stas:即使在繪圖案例中,VolatileImages通常會比BufferedImage明顯更快,這是因爲它實際上存儲在視頻RAM中,所有繪製調用都會在幕後轉換爲硬件加速調用。不要低估現代GPU的真實速度,特別是setColor()和drawLine()是瓶頸時您還可以從數組中創建BufferedImage代表你的顏色值,看看它是否能加快速度,至少它應該是並行化的微不足道的。 – 2010-10-13 20:12:02

0

根據你的代碼簡單的介紹一下一些優化建議:

  • 您正在爲每個驗證碼一個新的BufferedImage。我認爲你最好在ThreadLocal變量中爲每個線程保存一個BufferedImage和Graphics2D,並且在創建新線程時在上一個驗證碼上繪圖。
  • 您正在爲每個像素執行大量計算的大循環。您希望絕對減少在此循環中間完成的計算,例如做「colorRightDown.getRed()/ 255.0f」等的常量計算。在循環外
  • 考慮將所有浮點計算轉換爲等價的定點整數數學。這通常會稍微快一點,以便您可以使所有內容適合整數。
  • 使用BufferedImage.setRGB()的整數顏色值,而不是Graphics2D.setColor新的顏色 - 這將是更快,爲您節省大量GC壓力
  • 看看你是否可以減少隨機數每個像素的數量調用,我計算每個像素7 ....你可以逃避比那更少?你可能會更好地創建一個隨機整數並測試這些位的子集。
  • 在inner(i)循環中使用寬度而不是getImageWidth(),否則,您將爲每個像素不必要地調用getImageWidth。 (j)循環相同,但重要性較低。

我的猜測是,上述合併將獲得你遠遠超過在這個問題拋出額外的處理器..... :-)